从服务定期更新AppWidget

时间:2011-04-14 16:17:43

标签: android

这是我想要的AppWidget:

  1. 配置活动出现,当窗口小部件添加到屏幕//好到目前为止
  2. 保存配置后,启动服务以更新小部件//到目前为止
  3. 定期计划警报以运行更新窗口小部件的服务。 //在这里遇到麻烦
  4. 这已经严重地给了我一头白发,我不知道该怎么做了。如何从服务中设置AppWidget的更新速率?我可以从服务更新小部件,但是当我尝试设置警报时,它无法访问AppWidget上的onReceive()方法。

    以下是服务更新的代码:

    Intent updateWidget = new Intent();
    updateWidget.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
    updateWidget.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[]{appWidgetId});
    Uri data = Uri.withAppendedPath(Uri.parse(WeatWidgetProvider.URI_SCHEME +
     "://widget/id/"), String.valueOf(appWidgetId));
    updateWidget.setData(data);
    PendingIntent updatePend = PendingIntent.getBroadcast(this, 0, updateWidget, PendingIntent.FLAG_UPDATE_CURRENT);
    AlarmManager alarm = (AlarmManager)getSystemService(ALARM_SERVICE);
    alarm.setRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime()+ updateRate, updateRate, updatePend);
    

    在WidgetProviderClass的onreceive()中:

    public void onReceive(Context context, Intent intent){
      super.onReceive(context, intent);
      Log.d("OnReceive", "OnReceive called");
      String action = intent.getAction();
      Log.d("Action", "OnReceive:Action: " + action);
      if(AppWidgetManager.ACTION_APPWIDGET_DELETED.equals(action)){
        int appwidgetId = intent.getExtras().getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
        if(appwidgetId != AppWidgetManager.INVALID_APPWIDGET_ID){
          this.onDeleted(context, new int[] {appwidgetId});
        }
      } else if(AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)){
        if(!URI_SCHEME.equals(intent.getScheme())){
          final int[] appWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
          for(int appWidgetId:appWidgetIds){
            SharedPreferences prefs = context.getSharedPreferences(WeatForecastConfigure.WEATHER_PREF_NAME, Context.MODE_PRIVATE);
            update = prefs.getInt(WeatForecastConfigure.REFRESH_UPDATE, -1);
            System.out.println(update);
            if(update != -1){
              Intent widgetUpdate = new Intent();
              widgetUpdate.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
              widgetUpdate.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] { appWidgetId });
              // make this pending intent unique by adding a scheme to it
              widgetUpdate.setData(Uri.withAppendedPath(Uri.parse(WeatWidgetProvider.URI_SCHEME +
               "://widget/id/"), String.valueOf(appWidgetId)));
              PendingIntent newPending = PendingIntent.getBroadcast(context.getApplicationContext(), 0, widgetUpdate, PendingIntent.FLAG_UPDATE_CURRENT);
              // schedule the updating
              AlarmManager alarms = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
              alarms.setRepeating(AlarmManager.ELAPSED_REALTIME,
               SystemClock.elapsedRealtime(), WeatForecastConfigure.convertToMillis(update), newPending);
            }
          }
        }
        super.onReceive(context, intent);
      }else{
        super.onReceive(context, intent);
      }
    }
    

    对于onUpdate()评论的行是故意的。

    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds){
      Log.d("OnUpdate", "OnUpdate called");
      for (int appWidgetId : appWidgetIds) {
        // context.startService(new Intent(context,WeatService.class));
      }
      //super.onUpdate(context, appWidgetManager, appWidgetIds);
    }
    

    请帮忙。我不知道如何设置警报更新。无论是从配置类还是从服务中执行,它都不起作用。感谢。

2 个答案:

答案 0 :(得分:0)

我认为您需要在您的意图中使用标准URI方案,如下所示:

intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));

答案 1 :(得分:0)

我写了这一切,并意识到它可能会让你更加困惑,哦。好吧。

以下是我如何更新我的小部件的框架,它基于这段代码http://code.google.com/p/android-sky/source/browse/#svn%2Ftrunk%2FSky(特别是UpdateService类。)

主要区别在于我的代码

  1. 启动服务以执行更新
  2. 设置警报(广播待处理意图)以警告窗口小部件有关下一次更新的信息
  3. 更新小部件并停止服务
  4. 接收更新广播(在提供者onReceive中)并再次启动服务
  5. 您似乎试图告诉AppWidgetProvider启动onUpdate,我不确定这是否可行?

    以下是我在半伪代码中的表现:

    UpdateService类:

     //based on (an old) example http://code.google.com/p/android-sky/source/browse/#svn%2Ftrunk%2FSky however other methods I have tried have not been as reliable as this
     public void run() {
         //set the alarm for the next update
         AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
     long millis = System.currentTimeMillis();
    
         //one alarm to update them all, if you wanted to you could
         //add an extra appWidgetId then you might need to encode the intent
         //however so it is a unique PendingIntent
         Intent updateIntent = new Intent(ACTION_UPDATE_ALL);  //ACTION_UPDATE_ALL should be a constant somewhere that can be used to resolve this action com.packagename.ACTION_UPDATE_ALL
         PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, updateIntent, 0);
         // Schedule alarm, and force the device awake for this update
         alarmManager.set(AlarmManager.RTC, millis + updateFrequency * DateUtils.MINUTE_IN_MILLIS, pendingIntent);
         Log.d(TAG, "Next update should be at: " + DateFormat.format("h:mm:ss", millis + updateFrequency * DateUtils.MINUTE_IN_MILLIS));
    
    
         while (hasMoreUpdates()) {
            int appWidgetId = getNextUpdate();
            if (!(appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID)) {
                Uri appWidgetUri = ContentUris.withAppendedId(Agenda.getContentUri(context), appWidgetId);
    
                AppWidgetProviderInfo info = manager.getAppWidgetInfo(appWidgetId);  
                String providerName = info.provider.getClassName();
                //if the provider matches one of my widget classes, call the update method
                if (providerName.equals(Widget_4_1.class.getName())) {
                     remoteViews = Widget_4_1.buildUpdate(context, appWidgetUri, dateRows);
                }
    
                //perform more actions such as sending remoteViews to the AppWidgetManager
            }
        }
    }
    

    Widget_4_1课程:

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
            int[] appWidgetIds) {
    
        // If no specific widgets requested, collect list of all
        if (appWidgetIds == null) {
            appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(
                    context, AbstractWidget.class));
        }
    
        UpdateService.requestUpdate(appWidgetIds);
        Intent i = new Intent();
        i.setComponent(new ComponentName(context, UpdateService.class));
        context.startService(i);
    }
    
    //called from service
    public static RemoteViews buildUpdate(Context context, Uri appWidgetUri) {
        int appWidgetId = (int) ContentUris.parseId(appWidgetUri);
        RemoveViews remoteViews = someMethodToBuildView(appWidgetId );
        //return view to service
        return remoteViews;
    }
    
    public void onReceive(Context context, Intent intent) {
    
    final String action = intent.getAction();
    
        //when the alarm triggers, just update all your widgets, why handle them separately?
    if (action.equals(ACTION_UPDATE_ALL)) {
            AppWidgetManager manager = AppWidgetManager.getInstance(context);
        int[] appWidgetIds = manager.getAppWidgetIds(new ComponentName(context, getClass()));
        if(appWidgetIds.length>0){
                UpdateService.requestUpdate(appWidgetIds);
        Intent updateIntent = new Intent(context, UpdateService.class);
                updateIntent.setAction(action);
    
            context.startService(updateIntent);
        }
        }
        //else you could catch a specific action for updating a single widget and
        //tell your update service to do it manually
    }
    

    的AndroidManifest.xml:

    <application> 
         ...
        <receiver android:name="com.mypackage.Widget_4_1"
            android:label="@string/agenda_widget_name_4_1">
        <intent-filter>
                <!-- IMPORTANT, needs to match the ACTION_UPDATE_ALL string (e.g. a constant somewhere) -->
            <action android:name="com.packagename.UPDATE_ALL" />
        </intent-filter>
        <meta-data android:name="android.appwidget.provider"
                android:resource="@xml/widget_4_1" />
    </receiver>
        ...
    </application> 
    

    希望我没有让你困惑。

    由于此代码是从我的项目的各个部分复制/粘贴的,请原谅错字等,我会在指出时修复它们。