目前,我的AppWidgetProvider
有一个静态数据。它用于传递信息
public class MyAppWidgetProvider extends AppWidgetProvider {
// Key will be widget id
private static Map<Integer, Holder> holderMap = new java.util.concurrent.ConcurrentHashMap<Integer, Holder>();
public static int getClickedColumn(int appWidgetId) {
Holder holder = holderMap.get(appWidgetId);
if (holder == null) {
return -1;
}
return holder.clickedColumn;
}
public class AppWidgetRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
@Override
public void onDataSetChanged() {
int clickedColumn = MyAppWidgetProvider.getClickedColumn(mAppWidgetId);
调用
AppWidgetProvider
的静态方法在大多数情况下都可以正常工作。然而,有时,如果我把小部件放在主屏幕上,让它在那里呆上几个小时。当我回来查看
RemoteViewsService.RemoteViewsFactory
时,可能会随机得到以下错误。java.lang.ExceptionInInitializerError
at org.yccheok.project.gui.widget.AppWidgetRemoteViewsFactory.onDataSetChanged(AppWidgetRemoteViewsService.java:390)
at android.widget.RemoteViewsService$RemoteViewsFactoryAdapter.onDataSetChanged(RemoteViewsService.java:142)
at com.android.internal.widget.IRemoteViewsFactory$Stub.onTransact(IRemoteViewsFactory.java:49)
at android.os.Binder.execTransact(Binder.java:367)
at dalvik.system.NativeStart.run(Native Method)
Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:121)
at org.yccheok.project.gui.widget.MyAppWidgetProvider.<clinit>(MyAppWidgetProvider.java:564)
从
AppWidgetProvider
开始,我怀疑ListView
被操作系统破坏了?这是因为<clinit>
想在调用静态函数之前执行类初始化吗?这是否意味着,
MyAppWidgetProvider
可以随时被操作系统破坏,我们不应该在其中放置可共享的静态数据?如果是,那么在
AppWidgetRemoteViewsFactory
和MyAppWidgetProvider
之间共享数据的正确方式是什么?(除了使用文件或sharedpreferences之外) 最佳答案
远程视图工厂->AppWidgetProvider
可以使用广播完成从RemoteViewsFactory到AppWidgetProvider的通信,例如:
Intent intent = new Intent(ACTION_PROGRESS_OFF);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
AppWidgetProvider接收如下事件:
@Override
public void onReceive(final Context context, final Intent intent) {
// here goes the check if the app widget id is ours
final String action = intent.getAction();
if (ACTION_PROGRESS_OFF.equals(action)) {
// turn off the refresh spinner
当然,广播操作需要在清单中定义:
<receiver
android:name="...">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="myPackage.ACTION_PROGRESS_OFF" />
</intent-filter>
<meta-data ... />
</receiver>
AppWidgetProvider->远程视图工厂
与remoteviewsfactory(在您的情况下可能是最好的)通信的一种方法是按照您传递给remoteviewsadapter的服务的意图发送信息:
Intent intentRVService = new Intent(context, RemoteViewsService.class);
intentRVService.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
// let's put in some extra information we want to pass to the RemoteViewsFactory
intentRVService.putExtra("HELLO", "WORLD");
// when intents are compared, the extras are ignored, so we need to
// embed the extras into the data so that the extras will not be ignored
intentRVService.setData(Uri.parse(intentRVService.toUri(Intent.URI_INTENT_SCHEME)));
rv.setRemoteAdapter(appWidgetId, R.id.my_list, intentRVService);
rv.setEmptyView(R.id.my_list, android.R.id.empty);
// create the pending intent template for individual list items
...
rv.setPendingIntentTemplate(R.id.my_list, pendingIntentTemplate);
appWidgetMgr.notifyAppWidgetViewDataChanged(appWidgetId, R.id.my_list);
RemoteViewsService可以轻松地从意图检索信息并将其传递给RemoteViewsService.RemoteViewsFactory。
我不能百分之百确定您的小部件何时以及如何决定对数据进行排序,但我假设如果用户选择要排序的列,那么您必须在notifyappwidgetviewdatachanged的情况下完成更新周期,然后将该列一起传递。如果以后需要这些信息,就必须以某种方式存储这些信息(sharedpreferences)。