5

Ho un AppWidget che ha uno StackView contenuto al suo interno. Insieme a AppWidget, ho un servizio che viene avviato quando un utente aggiunge AppWidget alla sua schermata iniziale che esegue il polling dei nuovi dati ogni due ore. Quando il servizio trova nuovi dati, ho bisogno che avvisi il mio AppWidget e che passi anche a RemoteViewsService (che ha il mio RemoteViewsFactory) in modo che possa creare le viste necessarie per i nuovi dati.Passando un array di numeri interi da un AppWidget a un RemoteViewsService preesistente per il rendering da RemoteViewsFactory

Attualmente, quando il servizio trova nuovi dati, ho trasmesso al mio AppWidget che sono stati trovati nuovi dati, passando tali dati come una matrice di numeri interi all'interno di un intent.

Il mio metodo onReceive nel mio AppWidgetProvider estrae i dati, quindi eseguo il processo di impostazione di un nuovo intent che viene passato a RemoteViews per AppWidget. Il codice di esempio qui di seguito:

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

questo funziona la prima volta. I dati vengono visualizzati da RemoteViewsService/RemoteViewsFactory. I nuovi dati successivi non colpiscono il costruttore di RemoteViewsFactory perché il servizio per quel factory è già in esecuzione.

Come posso aggiornare i dati? Sento che dovrei usare onDataSetChanged, ma come potrei accedere all'intento che ho passato da onReceive di AppWidget?

Apprezzerei qualsiasi idea su come procedere correttamente. Grazie.

+0

Se posso ottenere onGetViewFactory nel RemoteViewsService a correre di nuovo, mi sarebbe in grado di ottenere i nuovi dati dal intento passato al dati. O se posso in qualche modo dire al servizio di aggiornare i suoi dati ... – Steven

risposta

3

La soluzione per un array intero passato a RemoteViewsFactory è stata risolta utilizzando un BroadcastReceiver. Ho esteso la mia RemoteViewsFactory per implementare il BroadcastReceiver (in particolare onReceive), e l'ho registrato con la mia applicazione nel costruttore per la fabbrica (questo significa anche che non l'ho registrato su onDestroy). Con ciò, sono stato in grado di trasmettere l'intento con l'array intero che avevo nella sezione onReceive del mio AppWidgetProvider e riceverlo all'interno di RemoteViewsFactory.

Assicuratevi di chiamare anche l'AppWidgetManager notifyAppWidgetViewDataChanged in modo che RemoteViewsFactory sappia che i dati che stava usando in precedenza sono stati invalidati e che un nuovo array intero viene presentato per creare nuove RemoteViews.

+0

Potresti per favore pubblicare un codice dettagliato su come hai implementato questo? Ho qualche problema a capirlo. Grazie per i suggerimenti! –

3

Per approfondire ulteriormente la soluzione di Steve sopra a beneficio di arne.jans e altri, ho implementato la soluzione di Steven da:

  • Estrazione del StackRemoteViewsFactory in un file di classe a sé stante
  • estendendolo con un BroadcastReceiver
  • attuazione del metodo onReceive() salvare nuovi dati a una variabile statica in cui la classe StackRemoteViewsFactory potrebbe anche accedere quando il suo getViewAt richiesti i dati
  • Trasmissione di tutti gli ID widget tramite Intent in modo da poter chiamare uno notifyAndUpdate di TUTTI i widget nel metodo onReceive().
  • Finalmente aggiunta la definizione standard per un ricevitore alla AndroidManifest.xml
1

non mi estendo RemoteViewFactory con un BroadcastReceiver, ma attuare BroadcastReceiver dinamica su di esso per passare una stringa da AppWidgetProvider a RemoteViewFactory.

come questo:

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

Un'altra alternativa è quella di utilizzare il file system o un database SQLite, per esempio

In AppWidgetProvider:

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 
} 
Problemi correlati