¿Cuál es la forma correcta de compartir datos entre AppWidgetProvider y RemoteViewsService.RemoteViewsFactory?

Actualmente, mi AppWidgetProvider está teniendo datos estáticos. Se utiliza para pasar información alrededor de AppWidgetProvider y RemoteViewsService.RemoteViewsFactory

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

Llamar el método estático de AppWidgetProvider funciona bien en la mayoría de la situación.

Sin embargo, a veces, si coloco el widget en la pantalla de inicio, dejarlo estar allí durante pocas horas. Cuando vuelva y escoll el ListView , puedo conseguir el error siguiente aleatoriamente.

 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) 

De <clinit> , sospecho que MyAppWidgetProvider es destruido por el sistema operativo? Esto causa que AppWidgetRemoteViewsFactory quiera realizar la inicialización de la clase, antes de llamar a la función estática?

¿Significa esto que MyAppWidgetProvider puede ser destruido en cualquier momento por el sistema operativo y no deberíamos colocar datos estáticos compartibles en él?

Si es así, ¿cuál es la forma correcta de compartir datos entre AppWidgetProvider y RemoteViewsService.RemoteViewsFactory ? (Además de usar File o SharedPreferences)

RemoteViewsFactory -> AppWidgetProvider

La comunicación desde RemoteViewsFactory a AppWidgetProvider se puede hacer usando Broadcasts, por ejemplo, como esto:

 Intent intent = new Intent(ACTION_PROGRESS_OFF); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId); LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent); 

El AppWidgetProvider recibe el evento de la siguiente manera:

 @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 

Por supuesto, la acción de difusión debe definirse en el manifiesto:

 <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

Una manera de comunicarse con RemoteViewsFactory (y en su caso probablemente la mejor) es enviar la información en la intención del servicio que está pasando a 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 puede recuperar fácilmente la información de la intención y pasarla a la RemoteViewsService.RemoteViewsFactory.

No estoy 100% seguro cuándo y cómo su widget decide clasificar los datos pero asumiría si el usuario escoge una columna para clasificar entonces usted tiene que pasar con el ciclo de la actualización con notifyAppWidgetViewDataChanged y después usted pasaría esa columna adelante. Si necesita esa información más tarde, entonces tendría que almacenar la información de alguna manera (SharedPreferences).

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.