Passing an array of integers from an AppWidget to an existing RemoteViewsService to render RemoteViewsFactory

I have an AppWidget that has a StackView in it. Along with AppWidget, I have a service that starts when a user adds my AppWidget to their desktop, which polls new data every two hours. When the service finds new data, I need it to report my AppWidget and also pass this data to the RemoteViewsService (which has RemoteViewsFactory) so that it can create the necessary views for the new data.

Currently, when the service finds new data, I passed it to AppWidget that the new data was found, passing this data as an array of integers within the intent.

My onReceive method in my AppWidgetProvider application retrieves this data, and then I go on to the process of setting up a new intent, which is passed by my RemoteViews for AppWidget. Sample code below:

public void onReceive( Context context, Intent intent ) { int[] appWidgetIds = appWidgetManager.getAppWidgetIds( new ComponentName( context, SampleAppWidgetProvider.class ) ); int[] sampleData = intent.getIntArrayExtra( Intent.EXTRA_TITLE ); for ( int i = 0; i < appWidgetIds.length; i++ ) { // RemoteViewsFactory service intent Intent remoteViewsFactoryIntent = new Intent( context, SampleAppWidgetService.class ); remoteViewsFactoryIntent.putExtra( AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i] ); remoteViewsFactoryIntent.setData( Uri.parse( remoteViewsFactoryIntent.toUri( Intent.URI_INTENT_SCHEME ) ) ); remoteViewsFactoryIntent.putExtra( Intent.EXTRA_TITLE, sampleData ); RemoteViews rv = new RemoteViews( context.getPackageName(), R.layout.widget_layout ); // Sync up the remoteviews factory rv.setRemoteAdapter( appWidgetIds[i], R.id.sample_widget, remoteViewsFactoryIntent ); rv.setEmptyView( R.id.sample_widget, R.id.empty_view ); appWidgetManager.updateAppWidget(appWidgetIds[i], rv); } super.onUpdate( context, appWidgetManager, appWidgetIds ); } 

This works for the first time. Data is displayed using RemoteViewsService / RemoteViewsFactory. Subsequent new data does not fall into the RemoteViewsFactory constructor because the service for this factory is already running.

How do I update the data? I feel like I should use onDataSetChanged, but how do I access the intent that I passed from AppWidget onReceive?

I would be grateful for the correct way to do this. Thanks.

+6
source share
4 answers

My solution to the integer array passed to RemoteViewsFactory was solved using BroadcastReceiver. I expanded RemoteViewsFactory to implement BroadcastReceiver (specifically onReceive) and registered it with my application in the constructor for factory (this also means that I did not register it with onDestroy). At the same time, I was able to translate the intent with the whole array that I had in the onReceive of my AppWidgetProvider, and get it in RemoteViewsFactory.

Make sure you also call the AppWidgetManager notifyAppWidgetViewDataChanged app so that the RemoteViewsFactory knows that the data it used earlier was invalid and a new array of integers was provided to create the new RemoteViews.

+3
source

To take a closer look at Steve's solution above in favor of arne.jans and others, I implemented Steven's solution:

  • Extract StackRemoteViewsFactory into a class file of its own
  • Extending with BroadcastReceiver
  • An implementation of the onReceive() method for storing new data in a static variable in which the StackRemoteViewsFactory class StackRemoteViewsFactory also access when its getViewAt required data
  • Passing all widget IDs with Intent so that I can call notifyAndUpdate all widgets in the onReceive() method.
  • Finally, I added a standard definition for the recipient on AndroidManifest.xml
+3
source

I did not extend RemoteViewFactory with BroadcastReceiver, but implemented a dynamic BroadcastReceiver on it to pass a string from AppWidgetProvider to RemoteViewFactory.

like this:

 public class MyWidgetProvider extends AppWidgetProvider { @Override public void onReceive(Context context, Intent intent) { super.onReceive(context, intent); String action = intent.getAction(); if (action.equals("android.appwidget.action.APPWIDGET_UPDATE")) { ..... } else if (action.equals("some.string.you.want.ACTION_TODO")) { String url = intent.getStringExtra("some.string.you.want.EXTRA_URL"); // Send broadcast intent to pass mUrl variable to the MyContentFactory. Intent broadcastIntent = new Intent("some.string.you.want.ACTION_UPDATE_URL"); broadcastIntent.putExtra("some.string.you.want.EXTRA_URL", url); context.sendBroadcast(broadcastIntent); } ..... } } public class MyContentFactory implements RemoteViewsService.RemoteViewsFactory { private Context mContext; private String mUrl; // target to update private BroadcastReceiver mIntentListener; public MyContentFactory(Context context, Intent intent) { mContext = context; setupIntentListener(); } @Override public void onDestroy() { teardownIntentListener(); } private void setupIntentListener() { if (mIntentListener == null) { mIntentListener = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // Update mUrl through BroadCast Intent mUrl = intent.getStringExtra("some.string.you.want.EXTRA_URL"); } }; IntentFilter filter = new IntentFilter(); filter.addAction("some.string.you.want.ACTION_UPDATE_URL"); mContext.registerReceiver(mIntentListener, filter); } } private void teardownIntentListener() { if (mIntentListener != null) { mContext.unregisterReceiver(mIntentListener); mIntentListener = null; } } } 
+1
source

Another alternative is to use a file system or sqlite database, for example.

In the AppWidgetProvider application:

  File file = new File(context.getCacheDir(), "filename that service also knows"); writeFile(file, "my content"); // impl. not shown; uses BufferedWriter.java 

In RemoteViewsService:

  File file = new File(context.getCacheDir(), "filename that service also knows"); if (file.exists()) { // handle params contained within file file.delete(); // clear for next run } 
+1
source

Source: https://habr.com/ru/post/897015/


All Articles