2011-11-30 49 views
4

我想編寫一個在小部件中顯示一些信息的應用程序,該信息應不時更新。不時意味着,我使用鬧鐘定時器觸發定期更新。所以繼承人問題:intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);爲廣播接收機意圖爲空。無法從BroadcastReceiver更新android小部件

這裏是我的控件提供者:

public class MyWidgetProvider extends AppWidgetProvider { 
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { 
     final int N = appWidgetIds.length;  
    for(int i=0; i<N; i++) { 
      int widgetId = appWidgetIds[i];   
      RemoteViews rViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);   
      Intent intent = new Intent(context.getApplicationContext(), TrafficService.class); 
      intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);    
      rViews.setTextViewText(R.id.TextView01, "" + System.currentTimeMillis());   
      appWidgetManager.updateAppWidget(widgetId, rViews); 
     } 
    } 
} 

,這是廣播接收器引起的問題:

public class TimeIntervalReceiver extends BroadcastReceiver { 
    @Override 
    public void onReceive(Context context, Intent intent) { 
// set new alarm timer (code cut out)  
     AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context.getApplicationContext()); 
     // PROBLEM BELOW! 
     int[] appWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);  
     if(appWidgetIds == null) Log.d("TRAFFIC", "oh SHIT"); 
     if(appWidgetIds != null && appWidgetIds.length > 0) { 
      for(int widgetId : appWidgetIds) { 
       RemoteViews rViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout); 
       rViews.setTextViewText(R.id.TextView01, "some data"); 
       appWidgetManager.updateAppWidget(widgetId, rViews); 
      } 
     } 
    } 
} 

這甚至solveable?

+0

同樣的問題在這裏... –

回答

0

當系統調用你的AppWidgetProvider實現,它填補了這些額外的意圖。

但是,當它調用具有沒有做的小部件廣播接收器,它不填寫此額外的意圖。

您將不得不使用另一種方法來傳送ID。也許你可以填寫他們的Intent這是警報火災時被解僱?

0

所以我改變了廣播接收機爲以下:

public class TimeIntervalReceiver extends BroadcastReceiver { 
    @Override 
    public void onReceive(Context context, Intent intent) { 
     Calendar c = Calendar.getInstance(); 
     c.add(Calendar.SECOND, Config.UPDATE_RATE);  
     Date d = new Date(c.getTimeInMillis()); 

     AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context.getApplicationContext()); 
     int[] appWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS); 

     if(appWidgetIds == null) Log.d("TRAFFIC", "oh SHIT"); // triggers :(
     if(appWidgetIds != null && appWidgetIds.length > 0) { 
      for(int widgetId : appWidgetIds) { 
       RemoteViews rViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout); 
       rViews.setTextViewText(R.id.TextView01, "someupdateddata"); 
       appWidgetManager.updateAppWidget(widgetId, rViews); 
      } 
     } 
     Intent i = new Intent(context, TimeIntervalReceiver.class); 
     i.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); // here i'd add the existing widget ids... 
     PendingIntent sender = PendingIntent.getBroadcast(context, 0, i, PendingIntent.FLAG_UPDATE_CURRENT); 

     AlarmManager aManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 
     aManager.set(AlarmManager.RTC, d.getTime(), sender); 
} 
} 

這仍然觸發 - 因爲第一報警定時器(需要被)設置,而無需知道插件-ID-陣列。 (例如通過onclickhandler)......有什麼辦法可以做到這一點嗎?

+0

你應該編輯的問題,而不是張貼另一個答案。無論如何,你可以在應用程序小部件提供程序本身設置**第一個**警報嗎? – Jong

+0

的問題在於,當另一個事件被觸發時,即在另一個廣播接收機中,第一個鬧鐘被設置。 – xenonite

7

大聲笑,我有我的答案...

只需更換:

int[] appWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS); 

通過

ComponentName thisWidget = new ComponentName(getApplicationContext(),MyWidgetProvider.class); 
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget); 
+0

真棒!我有一個非常類似的問題。謝謝!! – outkkast

0

疑惑:爲什麼你不只是覆蓋的的onReceive()方法WidgetProvider?由於AppWidgetProvider是從BroadcastReceiver擴展的,所以只要調用super.onReceive(),就完全合法。

你通過的onReceive得到(意圖)包含Widget的ID作爲一個額外的,如果它被稱爲由AppWidgetHost(啓動)。如果你自己調用它,你必須自己添加所需的附加功能。

這看起來是同時保持其原有的功能從任何其他活動觸發WidgetProvider一種優雅的方式。

記住:的AppWidgetProvider是一個方便的類的Widgets容易發展,但到核心,它只是一個廣播接收器。

我解決了它這樣的:

public class WidgetProvider extends AppWidgetProvider { 

    public static final String ACTION_RESTART_SERVICE = "ACTION_RESTART_SERVICE"; 

    @Override 
    public void onReceive(Context context, Intent intent) { 
    Log.d(TAG, "onEnabled() called."); 
    if (intent.getAction() != null && intent.getAction().equals(WidgetProvider.ACTION_RESTART_SERVICE)) 
    { 
     // Start service 
     Log.d(TAG, "ACTION_RESTART_SERVICE... Restarting service with designated update interval..."); 
     Intent i = new Intent(context, UpdateWidgetService.class); 
     service = startService(i, context, service); 
    } else 
    { 
     // Other intent, call super class 
     Log.d(TAG, "Not ACTION_RESTART_SERVICE... calling superclass onReceive()..."); 
     super.onReceive(context, intent); 
    } 
} 
} 

而在你的活動/片段:

/** 
* Restart the update service via WidgetProvider to reflect new profile and settings 
* @param context Context is required 
*/ 
private void restartService(Context context) 
{ 
    Intent intent = new Intent(context, 
      WidgetProvider.class); 
    intent.setAction(WidgetProvider.ACTION_RESTART_SERVICE); 

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) 
    { 
     // Send intents to all widget provider classes 
     intent.setClass(context, WidgetProviderSize1.class); 
     getActivity().sendBroadcast(intent); 
     intent.setClass(context, WidgetProviderSize2.class); 
     getActivity().sendBroadcast(intent); 
     intent.setClass(context, WidgetProviderSize3.class); 
     getActivity().sendBroadcast(intent); 
     intent.setClass(context, WidgetProviderSize4.class); 
     getActivity().sendBroadcast(intent); 
     intent.setClass(context, WidgetProviderSize5.class); 
     getActivity().sendBroadcast(intent); 

    } else 
     getActivity().sendBroadcast(intent); 

} 

看起來有點複雜,因爲我有豆形軟糖動態可調整大小的小部件和固定低於部件尺寸操作系統版本,但解決方案應該清楚。

更簡單的解決方案可能是發送一個android.appwidget.action.APPWIDGET_UPDATE廣播意圖,就像啓動器直接觸發WidgetProvider的onUpdate()一樣。

然後有一個完全不同的選項可用:讓Updateservice自己獲取WidgetID,因此不需要從更新意圖中獲取它們。這是確定的,如果所有的部件basicly共享相同的配置,並且如果配置有什麼變化都應該被更新:

/** 
* Get all Widget IDs of WidgetProviders used by this app 
* @param appWidgetManager AppWidgetManager to use 
* @return Array of widget IDs 
*/ 
private int[] getAppWidgetIDs(AppWidgetManager appWidgetManager) 
{ 
    int[] widgetIdsOfOneProviderSize1 = getAppIdsOfSingleProvider(appWidgetManager, WidgetProviderSize1.class); 
    int[] widgetIdsOfOneProviderSize2 = getAppIdsOfSingleProvider(appWidgetManager, WidgetProviderSize2.class); 
    int[] widgetIdsOfOneProviderSize3 = getAppIdsOfSingleProvider(appWidgetManager, WidgetProviderSize3.class); 
    int[] widgetIdsOfOneProviderSize4 = getAppIdsOfSingleProvider(appWidgetManager, WidgetProviderSize4.class); 
    int[] widgetIdsOfOneProviderSize5 = getAppIdsOfSingleProvider(appWidgetManager, WidgetProviderSize5.class); 
    int[] widgetIdsOfOneProvider = getAppIdsOfSingleProvider(appWidgetManager, WidgetProvider.class); 
    int allWidgetIds[] = new int[widgetIdsOfOneProviderSize1.length + widgetIdsOfOneProviderSize2.length 
           + widgetIdsOfOneProviderSize3.length + widgetIdsOfOneProviderSize4.length 
           + widgetIdsOfOneProviderSize5.length + widgetIdsOfOneProvider.length]; 
    int index = 0; 
    for (int id : widgetIdsOfOneProviderSize1) 
    { 
     allWidgetIds[index] = id; 
     index ++; 
    } 
    for (int id : widgetIdsOfOneProviderSize2) 
    { 
     allWidgetIds[index] = id; 
     index ++; 
    } 
    for (int id : widgetIdsOfOneProviderSize3) 
    { 
     allWidgetIds[index] = id; 
     index ++; 
    } 
    for (int id : widgetIdsOfOneProviderSize4) 
    { 
     allWidgetIds[index] = id; 
     index ++; 
    } 
    for (int id : widgetIdsOfOneProviderSize5) 
    { 
     allWidgetIds[index] = id; 
     index ++; 
    } 

    for (int id : widgetIdsOfOneProvider) 
    { 
     allWidgetIds[index] = id; 
     index ++; 
    } 

    return allWidgetIds; 
} 

private int[] getAppIdsOfSingleProvider(AppWidgetManager appWidgetManager, Class cls) 
{ 
    ComponentName thisWidget = new ComponentName(getApplicationContext(), 
      cls); 
    int[] widgetIdsOfOneProvider = appWidgetManager.getAppWidgetIds(thisWidget); 
    return widgetIdsOfOneProvider; 
} 

是的,我已經使用ArrayUtils把陣列一起......還有改進的餘地; - )