所以我在我写的appwidget中看到了一些奇怪的行为。
小部件本身非常简单 - 它从持久存储中读取一些值,然后将它们显示为文本。布局中没什么好看的 - 只有一个FrameLayout
根元素,其中有一些Linear Layout
和TextView
个孩子。
小部件具有与之关联的简单配置活动。
奇怪的行为是,在用户关闭配置活动后,窗口小部件最初将显示“问题加载窗口小部件”,然后在几秒钟后显示“Google声音搜索”按钮(并且单击按钮实际上会启动Google Sound Search)。然后,再过几秒钟,它最终会显示预期的显示。
我现在远离我的代码,所以我必须等到今晚才能发布代码片段。但是,与此同时,任何人都可以提供一些有关如何发生这种事情的见解吗?有没有人经历过这个?另一个小部件怎么能“劫持”我的?
谢谢, -Ron
答案 0 :(得分:1)
您的小部件存在一些问题,并且所有这些都有答案(尽管您没有发布任何代码,所以我的一些陈述基于假设):
"问题加载小部件":这是Android在初始化小部件并更新布局之前使用的默认视图。只需将以下行添加到widget xml配置中(以显示加载消息而不是问题消息):
android:initialLayout="@layout/my_cool_widget_loading_message"
如果窗口小部件显示错误的布局,那么您可能在窗口小部件的onReceive方法中遇到问题。无论广播是否针对特定小部件,都会为所有小部件调用onReceive。 Android的AppWidgetProvider通过appwidget Id过滤广播,并调度到其他方法(如onUpdate)。
另见:https://developer.android.com/reference/android/appwidget/AppWidgetProvider.html#onReceive(android.content.Context,android.content.Intent)。
如果你覆盖onReceive(我假设你这样做),你需要调用super.onReceive(Context,Intent)来确保你的其他方法不会接到其他小部件的调用。
现在配置小部件。如果您按照Google文档进行操作,那么一切都会正常运行。我所做的唯一改进是你引用的其他答案(https://stackoverflow.com/a/14991479/534471)。这不会发出两个广播。 setResult()/ finish()部分只会终止config Activity并让Android知道是否实际添加小部件(取决于结果是RESULT_CANCELED还是RESULT_OK。
从您自己的回答中我可以看出为什么您的代码无法正常工作。代码是:
Intent intent = new Intent();
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] {mAppWidgetId});
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_OK, intent);
sendBroadcast(intent);
finish();
首先,没有必要添加appWidgetId两次,使用AppWidgetManager.EXTRA_APPWIDGET_IDS版本并且你很好。其次,您使用相同的Intent作为Activity的结果返回。 AFAIK没有记录当你在Intent上设置动作时会发生什么,但我对Android小部件的体验是你需要完全坚持文档或者你最终会遇到奇怪的问题(比如那些你遇到了)。所以请使用两种不同的意图。 活动结果:
Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_OK, resultValue);
finish();
广播:
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE, null, this, MyWidget.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] {mAppWidgetId});
sendBroadcast(intent);
答案 1 :(得分:0)
问题是在我的配置Activity中,我最后有了这段代码:
Intent intent = new Intent();
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] {mAppWidgetId});
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_OK, intent);
sendBroadcast(intent);
finish();
documentation provided by google建议为额外的EXTRA_APPWIDGET_ID提供意图。
但是,同一文档说您必须通过创建RemoteView
并像这样调用AppWidgetManager.updateAppWidget()
来更新窗口小部件的视图:
RemoteViews views = new RemoteViews(context.getPackageName(),
R.layout.example_appwidget);
appWidgetManager.updateAppWidget(mAppWidgetId, views);
我不喜欢将表示逻辑放在配置活动和窗口小部件类中,因此我决定在配置活动结束时广播一个intent来告诉窗口小部件重绘自己。这就是我在活动结束时setResult()
和sendBroadcast()
的原因。文档进一步指出使用配置活动时不会调用onUpdate()
回调。所以这似乎是必要的。我将ACTION_APPWIDGET_UPDATE
和EXTRA_APPWIDGET_IDS
添加到intent中,以便触发onUpdate()
方法。这种做法是由SO answer推荐的(虽然没有包含在活动结果意图中 - 但我尝试将它们分开并且没有效果)。
现在我不确定“Google Sound Search”小部件究竟是如何进入的,我也不完全理解意图如何相互作用以产生观察结果的机制。但是,只要我使用文档中声明的代码替换上面的代码,就会正确更新窗口小部件。
Intent resultIntent = new Intent();
resultIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_OK, resultIntent);
finish();
这似乎与文档声明配置活动必须更新窗口小部件视图的说法相矛盾。简单地提供如下配置活动结果会触发窗口小部件中的onUpdate()
方法,从而允许窗口小部件重绘自身。我在运行API 23的模拟器上以及在运行Samsung的android风格的三星设备上确认了这种行为。