【问题标题】:How to update App Widget with list view from an Activity如何使用 Activity 中的列表视图更新 App Widget
【发布时间】:2016-03-12 11:40:31
【问题描述】:

我知道这已经被问过很多次了,但我从上到下浏览了文档,在这里阅读了所有答案,但没有一个有帮助。 老实说,每个答案都说明了如何解决这个问题。

现在回到我的问题。我想从某个活动中更新小部件列表视图,为此我创建了WidgetProvider#sendUpdateBroadcastToAllWidgets(),我从活动中调用了它。

它最终会调用onUpdate(),以便正确接收广播。但是视图没有刷新。

我也尝试调用AppWidgetManager#notifyAppWidgetViewDataChanged()并刷新WidgetFactory#onDataSetChanged()中的数据,但从未调用过该方法。

所以我猜这一切都不起作用,因为远程视图工厂被缓存但我不知道如何可靠地克服这个问题。有什么想法吗?

那么上下文呢?我总是必须提供一个,但我不太在乎哪一个。有关系吗?

谢谢

提供者

public class WidgetProvider extends AppWidgetProvider {

    public static void sendUpdateBroadcastToAllWidgets(Context context) {
        int allWidgetIds[] = AppWidgetManager.getInstance(context).getAppWidgetIds(new ComponentName(context, WidgetProvider.class));
        Intent intent = new Intent(context, WidgetProvider.class);
        intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, allWidgetIds);
        context.sendBroadcast(intent);
    }

    @Override
    public void onUpdate(Context context, AppWidgetManager widgetManager, int[] widgetIds) {
        for (int id : widgetIds) {
            updateWidget(context, widgetManager, id);
        }
        super.onUpdate(context, widgetManager, widgetIds);
    }

    @Override
    public void onDeleted(Context context, int[] widgetIds) {
        WidgetPreferences prefs = new WidgetPreferences(context);
        for (int widgetId : widgetIds) {
            prefs.getWidgetPreferences(widgetId).edit().clear().commit();
        }
        super.onDeleted(context, widgetIds);
    }

    private static void updateWidget(Context context, AppWidgetManager widgetManager, int widgetId) {
        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);

        // set list adapter
        Intent serviceIntent = new Intent(context, WidgetService.class);
        serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
        serviceIntent.setData(Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME)));
        views.setRemoteAdapter(android.R.id.list, serviceIntent);
        views.setEmptyView(android.R.id.list, android.R.id.empty);

        // set widget title
        WidgetDataCategory category = new WidgetPreferences(context).getSavedCategory(widgetId);
        views.setTextViewText(R.id.titleText, context.getString(category.titleResourceId()));

        // set onclick listener - we create a pending intent template and when an items is clicked
        // the intent is filled with missing data and sent
        Intent startActivityIntent = new Intent(context, SimplePersonDetailActivity.class);
        startActivityIntent.setData(Uri.parse(startActivityIntent.toUri(Intent.URI_INTENT_SCHEME)));
        startActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
        startActivityIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, startActivityIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        views.setPendingIntentTemplate(android.R.id.list, pendingIntent);

        // all hail to Google
        widgetManager.updateAppWidget(widgetId, views);
    }
}

工厂

public class WidgetFactory implements RemoteViewsService.RemoteViewsFactory {

    private Context context;
    private List<Person> people = new ArrayList<>();

    public WidgetFactory(Context context, Intent intent) {
        this.context = context;

        int widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
        if (widgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
            WidgetPreferences prefs = new WidgetPreferences(context);

            WidgetDataCategory category = prefs.getSavedCategory(widgetId);
            int numberOfItemsToShow = prefs.getSavedLimit(widgetId);

            people = category.filterAndSlice(new PersonDao(context).getAllForGroup(Constants.SIMPLE_GROUP_ID), numberOfItemsToShow);
        }
    }

    @Override
    public void onCreate() {}

    @Override
    public void onDataSetChanged() {}

    @Override
    public void onDestroy() {}

    @Override
    public int getCount() {
        return people.size();
    }

    @Override
    public RemoteViews getViewAt(int position) {
        Person person = people.get(position);
        BigDecimal amount = ListViewUtil.sumTransactions(new TransactionDao(context).getAllForPerson(person));

        RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.item_widget);
        remoteViews.setTextViewText(R.id.nameText, person.getName());
        remoteViews.setTextViewText(R.id.amountText, MoneyFormatter.withoutPlusPrefix().format(amount));

        // fill details for the onclick listener (updating the pending intent template
        // set in the WidgetProvider)
        Intent listenerIntent = new Intent();
        listenerIntent.putExtra(Constants.PERSON_ID, people.get(position).getId());
        remoteViews.setOnClickFillInIntent(R.id.widgetItem, listenerIntent);

        return remoteViews;
    }

    @Override
    public RemoteViews getLoadingView() {
        return null;
    }

    @Override
    public int getViewTypeCount() {
        return 1;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public boolean hasStableIds() {
        return true;
    }
}

【问题讨论】:

    标签: java android android-appwidget appwidgetprovider


    【解决方案1】:

    我会说notifyAppWidgetViewDataChanged 方法应该适合你。

    您必须构建AppWidgetManager 并获取appWidgetIds,然后只需在您的AppWidgetManager 上调用notifyAppWidgetViewDataChanged

    伪代码,

    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
    int appWidgetIds[] = appWidgetManager.getAppWidgetIds(
                               new ComponentName(context, WidgetProvider.class));
    appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.listview);
    

    更多信息,您可以查看我的答案here,其中包含 github 上的演示。

    【讨论】:

    • 我一定是有恶业什么的。我以前这样做过,但没有用,但我还是再次尝试了它,它可以工作:) 谢谢
    • 还有一件事,仅仅通知数据已经改变是不够的。仅此一项不适用于小部件的多个实例。您还需要致电updateWidget() 或通常是onUpdate() 中的代码
    【解决方案2】:

    我的项目中有一个小部件实现。我已经修改了下面的代码,以便可以从我的应用程序中的一个活动更改小部件中的数据。仅显示特定用例的基本代码。

    在这里,我的小部件中有一个带有文本的按钮。通过在我的 Activity 中单击登录按钮,我正在修改小部件中的按钮文本

    下面是我的AppWidgetProvider.java

    public class AppWidgetTrackAsset extends AppWidgetProvider{
          @Override
          public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
            // Perform this loop procedure for each App Widget that belongs to this provider
            final int N = appWidgetIds.length;
    
            for (int i=0; i<N; i++) {
                int appWidgetId = appWidgetIds[i];
                // Create an Intent to launch Activity
                Intent intent = new Intent(context, WidgetAlertActivity.class);
                PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
                // Get the layout for the App Widget and attach an on-click listener
                // to the button
                RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.app_widget_track_asset);
                views.setOnClickPendingIntent(R.id.sosButton, pendingIntent);
                // Tell the AppWidgetManager to perform an update on the current app widget
                appWidgetManager.updateAppWidget(appWidgetId, views);
            }
        }
        @Override
        public void onReceive(Context context, Intent intent) {
            super.onReceive(context, intent);
            Log.v(Constants.WIDGET_LOG, "onReceive called with " + intent.getAction());
            if (intent.getAction().equals("update_widget")) {
                // widget update started
                RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
                        R.layout.app_widget_track_asset);
                // Update text , images etc
                remoteViews.setTextViewText(R.id.sosButton, "My updated text");
                // Trigger widget layout update
                AppWidgetManager.getInstance(context).updateAppWidget(
                        new ComponentName(context, AppWidgetTrackAsset.class), remoteViews);
            }
        }
        @Override
        public void onEnabled(Context context) {
            // Enter relevant functionality for when the first widget is created
        }
    
        @Override
        public void onDisabled(Context context) {
            // Enter relevant functionality for when the last widget is disabled
        }
    }
    


    下面是我的活动,我在单击登录按钮时更新小部件按钮文本
    LoginActivity.java

    public class LoginActivity extends AppCompatActivity implements View.OnClickListener{
    
      Button loginButton;
      @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_login);
            loginButton=(Button)findViewById(R.id.loginButton);
            loginButton.setOnClickListener(this);
    
        }
        @Override
        public void onClick(View v) {
            if(v.getId() == R.id.loginButton){
                updateWidget();
            }
        }
        private void updateWidget(){
            try {
                Intent updateWidget = new Intent(this, AppWidgetTrackAsset.class);
                updateWidget.setAction("update_widget");
                PendingIntent pending = PendingIntent.getBroadcast(this, 0, updateWidget, PendingIntent.FLAG_CANCEL_CURRENT);
                pending.send();
            } catch (PendingIntent.CanceledException e) {
                Log.e(Constants.UI_LOG,"Error widgetTrial()="+e.toString());
            }
        }
    }
    


    应用小部件的布局是这样的

    app_widget_track_asset.xml

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/widgetbackground"
        android:padding="@dimen/widget_margin">
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/sosButton"
            android:text="SOS"
            android:textSize="20sp"
            android:layout_centerHorizontal="true"
            android:layout_centerVertical="true"
            />
    </RelativeLayout>
    

    以下是小部件的清单文件基本部分

    <receiver android:name=".appwidget.AppWidgetTrackAsset">
                <intent-filter>
                    <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
                </intent-filter>
    
                <meta-data
                    android:name="android.appwidget.provider"
                    android:resource="@xml/app_widget_track_asset_info" />
            </receiver>
    

    【讨论】:

      猜你喜欢
      • 2013-06-25
      • 2015-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-07
      • 2016-10-05
      相关资源
      最近更新 更多