Updating app widget using AlarmManager

匿名 (未验证) 提交于 2019-12-03 01:29:01

问题:

I am trying to update a Widget more frequently than the 30 minute restriction imposed by the 1.6docs. After reading nearly every post in SO, and the developer docs, and various other sources, I thought I had got to a point where i could implement it. And so, I tried, and failed. Since then, I have trawled yet more forums and solutions, and I cannot seem to get it to update.

I have an Update class that sets the AlarmManager:

public class Update extends Service{      @Override     public void onStart(Intent intent, int startId) {           String currentTemp = Battery.outputTemp;           String currentLevel = Battery.outputLevel;           String currentCard = Battery.outputCard;           String currentInternal = Battery.memory;           String currentRam = String.valueOf(Battery.outputRam).substring(0, 3) + "MB";            // Change the text in the widget           RemoteViews updateViews = new RemoteViews(            this.getPackageName(), R.layout.main);           //update temp           updateViews.setTextViewText(R.id.batteryTemp, currentTemp);            //update %           updateViews.setTextViewText(R.id.batteryLevel, currentLevel);                //update level           updateViews.setTextViewText(R.id.sdCard, currentCard);           //update internal memory           updateViews.setTextViewText(R.id.internal, currentInternal);           //update ram           updateViews.setTextViewText(R.id.ram, currentRam);            ComponentName thisWidget = new ComponentName(this, Widget.class);           AppWidgetManager manager = AppWidgetManager.getInstance(this);           manager.updateAppWidget(thisWidget, updateViews);      }     @Override     public IBinder onBind(Intent intent) {         // no need to bind         return null;     }  } 

This has caused my onReceive in my widget class to fire frequently (i have a toast to see when it fires), yet it carries no intent (the toast is meant to display this as they are received but it is blank).

I cannot figure it out (i'm a relative newb-2 months of slow android dev), and appreciate any insight you guys have.

heres my widget class for reference:

    public class Widget extends AppWidgetProvider {       @Override     public void onUpdate(Context context, AppWidgetManager appWidgetManager,             int[] appWidgetIds) {          AlarmManager alarmManager;         Intent intent = new Intent(context, Update.class);         PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,                 intent, PendingIntent.FLAG_UPDATE_CURRENT);         alarmManager = (AlarmManager) context                 .getSystemService(Context.ALARM_SERVICE);         Calendar cal = Calendar.getInstance();         cal.setTimeInMillis(System.currentTimeMillis());         cal.add(Calendar.SECOND, 10);         alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal                 .getTimeInMillis(), 5 * 1000, pendingIntent);          String currentTemp = Battery.outputTemp;         String currentLevel = Battery.outputLevel;         String currentCard = Battery.outputCard;         String currentInternal = Battery.memory;         String currentRam = String.valueOf(Battery.outputRam).substring(0, 3)                 + "MB";          // Change the text in the widget         RemoteViews updateViews = new RemoteViews(context.getPackageName(),                 R.layout.main);         // update temp         updateViews.setTextViewText(R.id.batteryTemp, currentTemp);         appWidgetManager.updateAppWidget(appWidgetIds, updateViews);         // update %         updateViews.setTextViewText(R.id.batteryLevel, currentLevel);         appWidgetManager.updateAppWidget(appWidgetIds, updateViews);         // update level         updateViews.setTextViewText(R.id.sdCard, currentCard);         appWidgetManager.updateAppWidget(appWidgetIds, updateViews);         // update internal memory         updateViews.setTextViewText(R.id.internal, currentInternal);         appWidgetManager.updateAppWidget(appWidgetIds, updateViews);         // update ram         updateViews.setTextViewText(R.id.ram, currentRam);         appWidgetManager.updateAppWidget(appWidgetIds, updateViews);         super.onUpdate(context, appWidgetManager, appWidgetIds);      }      public void onReceive(Context context, Intent intent) {          super.onReceive(context, intent);         Toast                 .makeText(context, intent.getAction() + context,                         Toast.LENGTH_LONG).show();         Bundle extras = intent.getExtras();         if (extras != null) {             AppWidgetManager appWidgetManager = AppWidgetManager                     .getInstance(context);             ComponentName thisAppWidget = new ComponentName(context                     .getPackageName(), Widget.class.getName());             int[] appWidgetIds = appWidgetManager                     .getAppWidgetIds(thisAppWidget);              onUpdate(context, appWidgetManager, appWidgetIds);         }      } } 

回答1:

I have an Update class that sets the AlarmManager:

No, you don't. AlarmManager appears nowhere in the code snippet.

You do have a reference to AlarmManager in the second code snippet. Problems there include:

  • You are setting a new repeating alarm every time the app widget updates

  • You are setting a 5 second frequency on the alarm, which is utter insanity

  • You are setting a 5 second frequency on a _WAKEUP alarm, which I think is grounds for your arrest in some jurisdictions

  • You have a pointless onReceive() method, even ignoring the temporary Toast

  • You are assuming that there will be an action string on the Intent in your Toast, but you do not specify an action string when you create the Intent that you put in the PendingIntent for the alarm

  • Your code refers to what I presume are static data members on a Battery class, but it is rather likely those are all empty/null... or at least they would be, if you had a sane frequency on the alarm



回答2:

This is my solution, how to automatically update widget more frequently than the 30 minutes. I use AlarmManager. Before you use AlarmManager for refreshing appwidget, make sure you know what you do, because this technique could drain the device's battery.

Read more about widget update in Android doc - especially about updatePeriodMillis parameter.

This is part of my Manifest.xml. I define custom action AUTO_UPDATE.

This is part of my AppWidget.java. In onReceive method, I handle my custom action AUTO_UPDATE. In onEnabled and onDisabled methods, I start/stop alarm.

public class AppWidget extends AppWidgetProvider {     public static final String ACTION_AUTO_UPDATE = "AUTO_UPDATE";      @Override     public void onReceive(Context context, Intent intent)     {         super.onReceive(context, intent);          if(intent.getAction().equals(ACTION_AUTO_UPDATE))         {             // DO SOMETHING         }          ...     }      @Override     public void onEnabled(Context context)     {         // start alarm         AppWidgetAlarm appWidgetAlarm = new AppWidgetAlarm(context.getApplicationContext());         appWidgetAlarm.startAlarm();     }      @Override     public void onDisabled(Context context)     {         // TODO: alarm should be stopped only if all widgets has been disabled          // stop alarm         AppWidgetAlarm appWidgetAlarm = new AppWidgetAlarm(context.getApplicationContext());         appWidgetAlarm.stopAlarm();     }      ... } 

This is my AppWidgetAlarm.java, which starts/stops alarm. Alarm manager sends broadcast to AppWidget.

public class AppWidgetAlarm {     private final int ALARM_ID = 0;     private final int INTERVAL_MILLIS = 10000;      private Context mContext;       public AppWidgetAlarm(Context context)     {         mContext = context;     }       public void startAlarm()     {         Calendar calendar = Calendar.getInstance();         calendar.add(Calendar.MILLISECOND, INTERVAL_MILLIS);          Intent alarmIntent = new Intent(AppWidget.ACTION_AUTO_UPDATE);         PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, ALARM_ID, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);          AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);         // RTC does not wake the device up         alarmManager.setRepeating(AlarmManager.RTC, calendar.getTimeInMillis(), INTERVAL_MILLIS, pendingIntent);     }       public void stopAlarm()     {         Intent alarmIntent = new Intent(AppWidget.ACTION_AUTO_UPDATE);         PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, ALARM_ID, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);          AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);         alarmManager.cancel(pendingIntent);     } } 


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!