如何使用活动中的列表视图更新App Widget [英] How to update App Widget with list view from an Activity

查看:224
本文介绍了如何使用活动中的列表视图更新App Widget的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I know this has been asked for many times but I went through the documentation from top to bottom, read all answers here and none of them helped. To be honest, each answer says something different about how to aproach this.

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

Now back to my question. I want to update the widget list view from some activity and I created WidgetProvider#sendUpdateBroadcastToAllWidgets() for this purpose which I call from the activity.

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

It eventually calls the onUpdate() so the broadcast is received correctly. But the views are not refreshed.

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

I also tried to call AppWidgetManager#notifyAppWidgetViewDataChanged() and refreshed the data in WidgetFactory#onDataSetChanged() but the method has never been called.

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

So I guess this all does not work because the remote views factory is cached but I don't know how to reliably overcome this. Any thoughts?

上下文怎么样?我总是要提供一个,但我真的不在乎哪一个。这有关系吗?

And what about contexts? I always have to supply one but I don't really care much which one. Does it matter?

谢谢

PROVIDER

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);
    }
}

FACTORY

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;
    }
}


推荐答案

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

I would say that notifyAppWidgetViewDataChanged method should work for you.

你必须建立 AppWidgetManager 并获取 appWidgetIds 然后只需在 AppWidgetManager上调用 notifyAppWidgetViewDataChanged / code>。

You have to build AppWidgetManager and get appWidgetIds and then just call notifyAppWidgetViewDataChanged on your AppWidgetManager.

伪代码,

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

更多信息,请查看我的答案这里包含github上的demo。

For more, you can checkout my answer here which contains demo on github.

这篇关于如何使用活动中的列表视图更新App Widget的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆