Inquiry related to AlarmManager and WakeLocks

2019-08-04 01:30发布

问题:

I am developing a native android app that run a backup operation every 30 mins.

I am using AlarmManager for this purpose and it works fine. Here is the code I am using to start the alarm:

public static void startSync(Context context) {
        alarmIntent = new Intent(context, AlarmReceiver.class);
        pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, 0);
        manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
       // int interval = 3600000;
        int interval =30000 ;
        manager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);

        ComponentName receiver = new ComponentName(context, SampleBootReceiver.class);
        PackageManager pm = context.getPackageManager();

        pm.setComponentEnabledSetting(receiver,
                PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                PackageManager.DONT_KILL_APP);
        Toast.makeText(context, "Sync Started", Toast.LENGTH_SHORT).show();
    }

And here is the the on receive method:

public class AlarmReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent arg1) {
        PowerManager pm = (PowerManager) context.getSystemService(context.POWER_SERVICE);
        PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My Tag");
        wl.acquire();
        Intent eventService = new Intent(context, SyncInBackground.class);
        context.startService(eventService);
        wl.release();
    }
}

I noticed that when my device isn't in standby, the operation took 5 seconds (I calculated it programmatically) but when the mobile is in standby mode it took 11 seconds. That's why I used wake_lock before running the backup operation in a background service, in order to make the app takes only 5 seconds.

But I still get the same results if the mobile in standby mode... it still takes 11 seconds and 5 seconds if not in standby mode.

What can I do to make my background service run the repeating alarm in 5 seconds instead of 11 seconds?

回答1:

The usual mistake: acquiring a wake lock in the OnReceive does nothing. The AlarmManager already holds a wake lock in OnReceive. Your way works out of pure luck, when/if it works. You have to either use a WakefulBroadcastReceiver or use a WakefulIntentService. The WIS will acquire a static wake lock which will be active between OnReceive returning and the service starting.

See my answer here: Wake Lock not working properly for links.



回答2:

The problem is that context.startService(eventService) is an asynchronous operation which is very likely to return in just a few milliseconds. This means that when you acquire a WakeLock in your onReceive method, you keep it just for a couple of milliseconds and you release before the service starts.

A way to solve this is to share the a wakelock between your BroadcastReceiver and the service that you're trying to launch. This is how the WakefulIntentService works but you can also do this yourself, for example, by creating a singleton WakelockManager with two methods, one for acquiring and one for releasing a wakelock, then have you BroadcastReceiver call the former and your service call the latter.

Also, remember that leaking wakelocks (by acquiring one but forgetting to release it) can have serious consequences in terms of battery usage.