2011-11-30 51 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把阵列一起......还有改进的余地; - )