Android 应用程序小部件:内容添加了两次

发布于 2024-10-08 23:34:04 字数 2311 浏览 0 评论 0原文

我正在编写一个应用程序小部件,我打算用项目列表填充该小部件。我试图通过扩展AppWidgetProvider来以简单的方式做到这一点。我看到一些奇怪的行为,其中项目列表被添加到父小部件两次。

代码如下:

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    Log.i("MyApp", "onUpdate called");

    DbAdapter dbAdapter = new DbAdapter(context);
    dbAdapter.open();

    final String[] columns = { DbTableCategory.KEY_NAME, DbTableCategory.KEY_CURRENTBAL };
    Cursor cursor = dbAdapter.getDb().query(DbTableCategory.TABLE_NAME, columns, null,
                        null, null, null, null);

    final int n = appWidgetIds.length;
    for (int i = 0; i < n; i++) {

        Log.i("MyApp", "Widget instance " + i);

        final int NUM_ITEMS = 4;

        int id = appWidgetIds[i];
        RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_layout);

        for (int c = 0; c < NUM_ITEMS; c++) {

            // get item info from db
            if (cursor.moveToPosition(c)) {
                RemoteViews itemView = new RemoteViews(context.getPackageName(), R.layout.widget_item);
                itemView.setTextViewText(R.id.widget_item_name, cursor.getString(0));
                itemView.setTextViewText(R.id.widget_item_amnt, cursor.getString(1));

                Log.i("MyApp", "Adding subview for item " + c);
                rv.addView(R.id.widget_container, itemView);
            }
        }

        appWidgetManager.updateAppWidget(id, rv);
    }

    cursor.close();
    dbAdapter.close();

我向列表中添加了四个项目,但实际上我在小部件中看到了八个项目(相同的四个项目出现了两次)。从日志输出来看,它告诉我有两个小部件实例(根据appWidgetIds数组,ID不同),因此外层循环运行了两次,内层循环运行了两次(对于每个项目)按预期运行四次。我不明白这一点,因为我确信我只将该小部件添加到主屏幕一次。它也不在任何其他主屏幕上 - 我使用的是默认的 HTC Sense 启动器。

即使我已经实例化该小部件两次,我也会为每个小部件实例创建一个新的 RemoteViews。我只是不明白为什么一个小部件实例似乎收到了两批项目。我错了什么?

附录:当我在模拟器中运行完全相同的代码时,它工作得很好,只报告了一个小部件实例。它仅显示实际手机(HTC Desire、Froyo)上的奇怪行为。

编辑:我已经在 文档 中注意到了这一点RemoteViews.addView():

如果 RemoteViews 的使用者可能会回收布局,请使用removeAllViews(int) 清除任何现有的子级。

是否会从 RemoteViews(...) 构造函数返回相同的 RemoteViews 实例?这可以解释为什么子视图被添加两次,但它不能解释为什么首先似乎有两个实例。

I am writing an app widget which I intend to populate with a list of items. I'm trying to do it the easy way by extending AppWidgetProvider. I am seeing some strange behaviour where the list of items gets added to the parent widget twice.

Here's the code:

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    Log.i("MyApp", "onUpdate called");

    DbAdapter dbAdapter = new DbAdapter(context);
    dbAdapter.open();

    final String[] columns = { DbTableCategory.KEY_NAME, DbTableCategory.KEY_CURRENTBAL };
    Cursor cursor = dbAdapter.getDb().query(DbTableCategory.TABLE_NAME, columns, null,
                        null, null, null, null);

    final int n = appWidgetIds.length;
    for (int i = 0; i < n; i++) {

        Log.i("MyApp", "Widget instance " + i);

        final int NUM_ITEMS = 4;

        int id = appWidgetIds[i];
        RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_layout);

        for (int c = 0; c < NUM_ITEMS; c++) {

            // get item info from db
            if (cursor.moveToPosition(c)) {
                RemoteViews itemView = new RemoteViews(context.getPackageName(), R.layout.widget_item);
                itemView.setTextViewText(R.id.widget_item_name, cursor.getString(0));
                itemView.setTextViewText(R.id.widget_item_amnt, cursor.getString(1));

                Log.i("MyApp", "Adding subview for item " + c);
                rv.addView(R.id.widget_container, itemView);
            }
        }

        appWidgetManager.updateAppWidget(id, rv);
    }

    cursor.close();
    dbAdapter.close();

I add four items to the list, but I actually see eight items in the widget (the same four appearing twice). From the log output, it is telling me that there are two instances of the widget (according to the appWidgetIds array, and the IDs are different), so the outer loop is running twice, and the inner loop (for each item) is running four times as expected. I don't understand this, as I'm positive I've only added the widget to my home screen once. It's not on any of the other home screens either - I'm using the default HTC Sense launcher.

Even if I had instantiated the widget twice, I'm creating a new RemoteViews for each widget instance. I just don't understand why the one widget instance seems to be receiving two lots of items. What am I getting wrong?

Addendum: when I run the exact same code in the emulator, it works just fine, with just one widget instance being reported. It's only showing the strange behaviour on the actual phone (HTC Desire, Froyo).

Edit: I've since noticed this in the documentation for RemoteViews.addView():

In cases where consumers of RemoteViews may recycle layouts, use removeAllViews(int) to clear any existing children.

Could it be that the same RemoteViews instance is being returned from the RemoteViews(...) constructor? That would explain why the child views are being added twice, but it would not explain why there seem to be two instances in the first place.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦罢 2024-10-15 23:34:04

关于您的小部件返回两个 appWidgetId 的第一个问题:
当小部件崩溃时(特别是在配置屏幕上或在小部件完全放置之前),我遇到了类似的情况。桌面应用程序仍将包含有关它的信息,但不会显示它。

第二个(主要)问题可能是由布局视图的回收引起的,我的猜测是 R.id.widget_container 没有清理干净。所以你可能应该

rv.removeAllViews(R.id.widget_container);

在 for 循环之前调用:。

此外,我建议从游标获取返回的行数(cursor.getCount()),而不是对其进行硬编码(代码中的NUM_ITEMS = 4)。

The first problem about your widget returning two appWidgetIds:
I had similar situations when the widget crash (especially on configuration screens or before the widget was fully placed). The desktop app will still contain information about it, but it won't display it.

The second (main) problem is probably caused by recycling of layout views, my guess is that R.id.widget_container is not cleaned up. So you probably should call:

rv.removeAllViews(R.id.widget_container);

before the for loop.

In addition I would suggest getting the number of returned rows from the cursor (cursor.getCount()) and not hard-coding it (NUM_ITEMS = 4 in your code).

晚雾 2024-10-15 23:34:04

我遇到了同样的问题,对我有用的解决方案是从 widget_container 中删除所有内部子级,因为在调用 rv.removeAllViews(R.id.widget_container); 时,该容器最初应该没有子级以免发生冲突。

I have faced the same problem, the solution which worked for me is to delete any inner children from the widget_container because when calling rv.removeAllViews(R.id.widget_container); that container should initially have no children in order for no conflicts to happen.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文