2016-03-12 20 views
13

So che è stato chiesto più volte ma ho esaminato la documentazione da cima a fondo, ho letto tutte le risposte qui e nessuna di queste ha aiutato. Ad essere onesti, ogni risposta dice qualcosa di diverso su come violare questo.Come aggiornare il widget dell'app con la visualizzazione elenco da un'attività

Ora torna alla mia domanda. Voglio aggiornare la vista elenco widget da alcune attività e ho creato WidgetProvider#sendUpdateBroadcastToAllWidgets() per questo scopo che chiamo dall'attività.

Alla fine chiama lo onUpdate() in modo che la trasmissione venga ricevuta correttamente. Ma i punti di vista non sono aggiornati.

Ho anche provato a chiamare AppWidgetManager#notifyAppWidgetViewDataChanged() e aggiornato i dati in WidgetFactory#onDataSetChanged() ma il metodo non è mai stato chiamato.

Quindi immagino che tutto questo non funzioni perché il factory delle viste remote è memorizzato nella cache ma non so come superarlo in modo affidabile. qualche idea?

E per quanto riguarda i contesti? Devo sempre fornirne uno, ma non mi interessa molto quale. Importa?

Grazie

PROVIDER

public class WidgetProvider extends AppWidgetProvider { 

    public static void sendUpdateBroadcastToAllWidgets(Context context) { 
     int allWidgetIds[] = AppWidgetManager.getInstance(context).getAppWidgetIds(new ComponentName(context, WidgetProvider.class)); 
     Intent intent = new Intent(context, WidgetProvider.class); 
     intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 
     intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, allWidgetIds); 
     context.sendBroadcast(intent); 
    } 

    @Override 
    public void onUpdate(Context context, AppWidgetManager widgetManager, int[] widgetIds) { 
     for (int id : widgetIds) { 
      updateWidget(context, widgetManager, id); 
     } 
     super.onUpdate(context, widgetManager, widgetIds); 
    } 

    @Override 
    public void onDeleted(Context context, int[] widgetIds) { 
     WidgetPreferences prefs = new WidgetPreferences(context); 
     for (int widgetId : widgetIds) { 
      prefs.getWidgetPreferences(widgetId).edit().clear().commit(); 
     } 
     super.onDeleted(context, widgetIds); 
    } 

    private static void updateWidget(Context context, AppWidgetManager widgetManager, int widgetId) { 
     RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget); 

     // set list adapter 
     Intent serviceIntent = new Intent(context, WidgetService.class); 
     serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId); 
     serviceIntent.setData(Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME))); 
     views.setRemoteAdapter(android.R.id.list, serviceIntent); 
     views.setEmptyView(android.R.id.list, android.R.id.empty); 

     // set widget title 
     WidgetDataCategory category = new WidgetPreferences(context).getSavedCategory(widgetId); 
     views.setTextViewText(R.id.titleText, context.getString(category.titleResourceId())); 

     // set onclick listener - we create a pending intent template and when an items is clicked 
     // the intent is filled with missing data and sent 
     Intent startActivityIntent = new Intent(context, SimplePersonDetailActivity.class); 
     startActivityIntent.setData(Uri.parse(startActivityIntent.toUri(Intent.URI_INTENT_SCHEME))); 
     startActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP); 
     startActivityIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId); 
     PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, startActivityIntent, PendingIntent.FLAG_UPDATE_CURRENT); 
     views.setPendingIntentTemplate(android.R.id.list, pendingIntent); 

     // all hail to Google 
     widgetManager.updateAppWidget(widgetId, views); 
    } 
} 

FABBRICA

public class WidgetFactory implements RemoteViewsService.RemoteViewsFactory { 

    private Context context; 
    private List<Person> people = new ArrayList<>(); 

    public WidgetFactory(Context context, Intent intent) { 
     this.context = context; 

     int widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); 
     if (widgetId != AppWidgetManager.INVALID_APPWIDGET_ID) { 
      WidgetPreferences prefs = new WidgetPreferences(context); 

      WidgetDataCategory category = prefs.getSavedCategory(widgetId); 
      int numberOfItemsToShow = prefs.getSavedLimit(widgetId); 

      people = category.filterAndSlice(new PersonDao(context).getAllForGroup(Constants.SIMPLE_GROUP_ID), numberOfItemsToShow); 
     } 
    } 

    @Override 
    public void onCreate() {} 

    @Override 
    public void onDataSetChanged() {} 

    @Override 
    public void onDestroy() {} 

    @Override 
    public int getCount() { 
     return people.size(); 
    } 

    @Override 
    public RemoteViews getViewAt(int position) { 
     Person person = people.get(position); 
     BigDecimal amount = ListViewUtil.sumTransactions(new TransactionDao(context).getAllForPerson(person)); 

     RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.item_widget); 
     remoteViews.setTextViewText(R.id.nameText, person.getName()); 
     remoteViews.setTextViewText(R.id.amountText, MoneyFormatter.withoutPlusPrefix().format(amount)); 

     // fill details for the onclick listener (updating the pending intent template 
     // set in the WidgetProvider) 
     Intent listenerIntent = new Intent(); 
     listenerIntent.putExtra(Constants.PERSON_ID, people.get(position).getId()); 
     remoteViews.setOnClickFillInIntent(R.id.widgetItem, listenerIntent); 

     return remoteViews; 
    } 

    @Override 
    public RemoteViews getLoadingView() { 
     return null; 
    } 

    @Override 
    public int getViewTypeCount() { 
     return 1; 
    } 

    @Override 
    public long getItemId(int position) { 
     return position; 
    } 

    @Override 
    public boolean hasStableIds() { 
     return true; 
    } 
} 

risposta

6

direi che notifyAppWidgetViewDataChanged metodo dovrebbe funzionare per voi.

È necessario creare AppWidgetManager e ottenere appWidgetIds e quindi chiamare semplicemente notifyAppWidgetViewDataChanged sul AppWidgetManager.

pseudo codice,

AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); 
int appWidgetIds[] = appWidgetManager.getAppWidgetIds(
          new ComponentName(context, WidgetProvider.class)); 
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.listview); 

Per di più, è possibile verifica la mia risposta here che contiene demo su github.

+0

Devo avere un brutto karma o qualcosa del genere. Ho fatto questo prima e non ha funzionato, ma ho provato di nuovo comunque e funziona :) Grazie – user219882

+0

E ancora una cosa, non è sufficiente solo notificare che i dati sono cambiati. Questo da solo non funziona per più istanze di un widget. Devi anche chiamare 'updateWidget()' o in generale il codice che si trova in 'onUpdate()' – user219882

+0

come reinserirai il codice in 'onUpdate()'? – natsumiyu

2

ho avuto un'implementazione widget nel mio progetto. Ho modificato il codice seguente in modo che i dati nel widget possano essere modificati da una delle mie attività nell'applicazione. Mostra solo il codice essenziale per il tuo caso d'uso specifico.

Qui sto avendo un pulsante con il testo nel mio widget. Attraverso il pulsante login click nella mia attività, sto modificando il testo del pulsante nel mio widget di

Qui di seguito è il mio AppWidgetProvider.java classe

public class AppWidgetTrackAsset extends AppWidgetProvider{ 
     @Override 
     public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { 
     // Perform this loop procedure for each App Widget that belongs to this provider 
     final int N = appWidgetIds.length; 

     for (int i=0; i<N; i++) { 
      int appWidgetId = appWidgetIds[i]; 
      // Create an Intent to launch Activity 
      Intent intent = new Intent(context, WidgetAlertActivity.class); 
      PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); 
      // Get the layout for the App Widget and attach an on-click listener 
      // to the button 
      RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.app_widget_track_asset); 
      views.setOnClickPendingIntent(R.id.sosButton, pendingIntent); 
      // Tell the AppWidgetManager to perform an update on the current app widget 
      appWidgetManager.updateAppWidget(appWidgetId, views); 
     } 
    } 
    @Override 
    public void onReceive(Context context, Intent intent) { 
     super.onReceive(context, intent); 
     Log.v(Constants.WIDGET_LOG, "onReceive called with " + intent.getAction()); 
     if (intent.getAction().equals("update_widget")) { 
      // widget update started 
      RemoteViews remoteViews = new RemoteViews(context.getPackageName(), 
        R.layout.app_widget_track_asset); 
      // Update text , images etc 
      remoteViews.setTextViewText(R.id.sosButton, "My updated text"); 
      // Trigger widget layout update 
      AppWidgetManager.getInstance(context).updateAppWidget(
        new ComponentName(context, AppWidgetTrackAsset.class), remoteViews); 
     } 
    } 
    @Override 
    public void onEnabled(Context context) { 
     // Enter relevant functionality for when the first widget is created 
    } 

    @Override 
    public void onDisabled(Context context) { 
     // Enter relevant functionality for when the last widget is disabled 
    } 
} 


Qui di seguito è la mia attività in cui sto aggiornando il testo del pulsante widget sul click del mio login pulsante
LoginActivity.java

public class LoginActivity extends AppCompatActivity implements View.OnClickListener{ 

    Button loginButton; 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_login); 
     loginButton=(Button)findViewById(R.id.loginButton); 
     loginButton.setOnClickListener(this); 

    } 
    @Override 
    public void onClick(View v) { 
     if(v.getId() == R.id.loginButton){ 
      updateWidget(); 
     } 
    } 
    private void updateWidget(){ 
     try { 
      Intent updateWidget = new Intent(this, AppWidgetTrackAsset.class); 
      updateWidget.setAction("update_widget"); 
      PendingIntent pending = PendingIntent.getBroadcast(this, 0, updateWidget, PendingIntent.FLAG_CANCEL_CURRENT); 
      pending.send(); 
     } catch (PendingIntent.CanceledException e) { 
      Log.e(Constants.UI_LOG,"Error widgetTrial()="+e.toString()); 
     } 
    } 
} 


layout per app widget va in questo modo

app_widget_track_asset.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:background="@drawable/widgetbackground" 
    android:padding="@dimen/widget_margin"> 
    <Button 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:id="@+id/sosButton" 
     android:text="SOS" 
     android:textSize="20sp" 
     android:layout_centerHorizontal="true" 
     android:layout_centerVertical="true" 
     /> 
</RelativeLayout> 

Di seguito è la parte essenziale file manifesto per il widget di

<receiver android:name=".appwidget.AppWidgetTrackAsset"> 
      <intent-filter> 
       <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> 
      </intent-filter> 

      <meta-data 
       android:name="android.appwidget.provider" 
       android:resource="@xml/app_widget_track_asset_info" /> 
     </receiver>