2016-03-12 5 views
13

Я знаю, что это было задано много раз, но я просмотрел документацию сверху донизу, прочитал все ответы здесь, и никто из них не помог. Чтобы быть честным, каждый ответ говорит о чем-то другом о том, как это подходить.Как обновить виджет приложений с видом списка из Activity

Теперь вернемся к моему вопросу. Я хочу обновить вид списка виджетов из некоторой активности, и для этой цели я создал WidgetProvider#sendUpdateBroadcastToAllWidgets(), который я вызываю из этой операции.

В конечном итоге он вызывает onUpdate(), поэтому передача принимается правильно. Но взгляды не освежаются.

Я также попытался позвонить AppWidgetManager#notifyAppWidgetViewDataChanged() и обновил данные в WidgetFactory#onDataSetChanged(), но метод так и не был вызван.

Так что я думаю, что все это не работает, потому что фабрика удаленных просмотров кэширована, но я не знаю, как это можно преодолеть. Есть предположения?

А как насчет контекстов? Я всегда должен поставлять один, но мне не очень нравится, какой из них. Это имеет значение?

Благодаря

ПРОВАЙДЕР

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

ФАБРИКА

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

ответ

6

Я бы сказал, что notifyAppWidgetViewDataChanged метод должен работать для вас.

Вы должны построить AppWidgetManager и получить appWidgetIds, а затем просто позвонить notifyAppWidgetViewDataChanged на AppWidgetManager.

псевдокоде

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

Более подробную информацию, вы можете оформить свой ответ here, который содержит демо на GitHub.

+0

У меня должна быть плохая карма или еще что-то. Я сделал это раньше, и это не сработало, но я все равно попробовал его, и он работает :) Спасибо – user219882

+0

И еще одно: недостаточно просто сообщить, что данные изменились. Это одно не работает для нескольких экземпляров виджета. Вам также нужно вызвать 'updateWidget()' или вообще код, который находится в 'onUpdate()' – user219882

+0

, как вы снова код в 'onUpdate()'? – natsumiyu

2

Я имел реализацию виджета в моем проекте. Я изменил приведенный ниже код, чтобы данные в виджетах можно было изменить из одного из моих приложений Activity. Показывается только основной код для вашего конкретного случая использования.

Здесь у меня есть кнопка с текстом в моем виджете. Через вход на нажатие кнопки в моей деятельности, я модифицируя текст кнопки в моем виджете

Ниже мой AppWidgetProvider.java класс

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


Ниже моя активность, где я обновить текст кнопки виджета на щелчку моего логина кнопка
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()); 
     } 
    } 
} 


Макет для приложения виджет идет как этот

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> 

Ниже файл манифеста существенная часть для виджета

<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> 
Смежные вопросы