Pre API 19, the go-to method for updating a Widget faster than the updatePeriodMillis
minimum time of 30 minutes was to use an AlarmManager
and a BroadcastReceiver
to receive the Intent after the specified interval used when setting up the AlarmManager.
Currently, using the below code, the Widget is updated, but as of Android 5.1, using .setRepeating() with a repeat interval of less than 60000ms will automatically have its interval set to at least 60000ms.
Setting alarm in Widgets onEnabled():
AlarmManager am= (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmManagerBroadcastReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
//After after 3 seconds
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+ 3000, 1000 , pi);
then in the AlarmManagerBroadcastReceiver's onReceive():
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "TAG");
//Acquire the lock
wl.acquire();
/*
* ......
* Update Widgets RemoteViews
*/
wl.release();
In the docs for setRepeating() it says:
Note: as of API 19, all repeating alarms are inexact. If your application needs precise delivery times then it must use one-time exact alarms, rescheduling each time as described above. Legacy applications whose targetSdkVersion is earlier than API 19 will continue to have all of their alarms, including repeating alarms, treated as exact.
it also now states:
Schedule a repeating alarm. Note: for timing operations (ticks, timeouts, etc) it is easier and much more efficient to use
Handler
So how would you go about updating the Widgets Remoteviews using a Handler? How would you get it to stop when the device is put to sleep to conserve battery?
Are there any other suggested ways to update a Widget?
From API level 21 JobScheduler is recommended to handle these kind of periodic updates.
Define the job in a JobService:
public class UpdateJob extends JobService {
public static int JOB_ID=9;
@Override
public boolean onStartJob(JobParameters params) {
Toast.makeText(getApplicationContext(),"update",Toast.LENGTH_SHORT).show();
//call handler, create thread, asynctask etc
return false;
}
@Override
public boolean onStopJob(JobParameters params) {
return false;
}
}
Register it in the manifest:
<service android:name=".UpdateJob"
android:permission="android.permission.BIND_JOB_SERVICE" />
Schedule the job e. g. in an Activity:
JobScheduler mJobScheduler = (JobScheduler)
getSystemService(Context.JOB_SCHEDULER_SERVICE);
JobInfo.Builder builder = new JobInfo.Builder( UpdateJob.JOB_ID,
new ComponentName( getApplicationContext(), UpdateJob.class ) );
builder.setPeriodic(60 * 60 * 1000); // every hour
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); // only when network is available
if( mJobScheduler.schedule( builder.build() ) <= 0 )
{
//error, cant be scheduled
}
//later e.g. when update is disabled
mJobScheduler.cancel(UpdateJob.JOB_ID);
JobInfo.Builder has lots of options to customize when your job is triggered e.g. it can depend on network and device state.
On lower APIs JobSchedulerCompat or GCM Network Manager can be used as an alternative to this, they both work pretty much the same way as shown above.
+one more
For dealing with an BroadcastReceiver which acquires wakelock there is a "helper" class in the Support Library, WakefulBroadcastReceiver.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With