Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Updating a Widget at short intervals using API 19+

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?

like image 818
Orbit Avatar asked Dec 17 '15 01:12

Orbit


1 Answers

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.

like image 119
csenga Avatar answered Nov 08 '22 18:11

csenga