I have a service that performs requests to the network at intervals of a minute. I was told to run it when I turn on the device. I did this. Now we need to make it work in standby mode and I can't understand anything, even the documentation. Everywhere they write about getting WakeLock and calling acquire , but they don’t write where to write it.

Once again: the service should start once both when the device is turned on and when the application is started. And if the device turns on and the user opens the application? Will start two services?

My BroadCastReceiver

 public class BootReceiver extends WakefulBroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { Intent serviceIntent = new Intent(context, NotificationsService.class); startWakefulService(context, serviceIntent); } } } 

Service

 public class NotificationsService extends IntentService { //блабла public NotificationsService(){ super("NotificationService"); } public void onCreate() { super.onCreate(); Log.d(LOG_TAG, "onCreate"); pref = getApplicationContext().getSharedPreferences("settings", Context.MODE_PRIVATE); configEditor = pref.edit(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d(LOG_TAG, "onStartCommand"); new Thread(){ @Override public void run() { connectWithIntervale(); } }.start(); return super.onStartCommand(intent, flags, startId); } public void connectWithIntervale(){ try { TimeUnit.MINUTES.sleep(1) } catch(Exception ignored) {} //запрос в сеть } @Override protected void onHandleIntent(Intent intent) { PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE); PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "NotificationWL"); wakeLock.acquire(); BootReceiver.completeWakefulIntent(intent); } 

I start service from activity so

 Intent i = new Intent(context, NotificationsService.class); startService(i); 

What else to do? Or is that all? I do not understand anything, the receiver will start the service when it is turned on, and then what will the activity do?

    2 answers 2

    The invention of bikes with WakeLock highly discouraged, since reduces the work of Doze Mode to nothing, eats battery and generally bad. For periodic tasks in the background, use the Firebase Job Dispatcher , or evernote / android-job . If you need to get new data from the server, then use FCM , this is a much more optimized solution.


    Approximate code for Firebase Job Dispatcher , here is an additional FAQ on it.

    In BootReceiver and onCreate in MainActivity :

      FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(context)); Job myJob = dispatcher.newJobBuilder() // the JobService that will be called .setService(MyJobService.class) // uniquely identifies the job .setTag("request") // recurring job .setRecurring(true) // run even after reboot .setLifetime(Lifetime.FOREVER) // start between 0 and 60 seconds from now .setTrigger(Trigger.executionWindow(0, 60)) // don't overwrite an existing job with the same tag .setReplaceCurrent(false) // retry with exponential backoff .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL) // run on an any network .setConstraints(Constraint.ON_ANY_NETWORK) .build(); dispatcher.schedule(myJob); 

    An example of the MyJobService can be viewed in the Job Dispatcher documentation, it runs the network request itself, do not forget to register it in the manifest.

    Such a Job will approximately guarantee a request about once a minute. I repeat that this is too often and this is a bad approach, it is better to use FCM . About limitations Doze Mode can be read here .

    • Do not quite understand. Service, receiver, where to write? Firebase Job Dispatcher will work when the screen is off? - Flippy
    • @Flippy, updated the answer - EgorD
    • I tried FirebaseJobDispatcher + Volley for queries in general. When the screen is off, notifications do not come. Does not fit? - Flippy
    • I need the service to work in standby too - Flippy

    Your task is to create a schedule to start your service. When you turn on the device (ie, ACTION_BOOT_COMPLETED) or when you start the Activity, you call:

     void setUpSchedule(Context context){ AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(context, BootReceiver.class); intent.setAction(START_NETWORK_UPDATES); PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); alarmManager.setInexactRepeating( AlarmManager.RTC_WAKEUP, new Date().getTime(), // с текущего момента TimeUnit.MINUTES.toMillis(1), // раз в минуту alarmIntent); } 

    In BootReceiver, the schedule works, the receiver creates a lok for you (you don’t need to create it) and until you keep saying that the work is finished, you start the service:

     @Override public void onReceive(Context context, Intent intent) { if (START_NETWORK_UPDATES.equals(intent.getAction())) { Intent serviceIntent = new Intent(context, NotificationsService.class); startWakefulService(context, serviceIntent); } } 

    In the NotificationsService process the launch from the receiver, how to finish, inform, the receiver itself will release the lock:

     @Override protected void onHandleIntent(Intent intent) { connectWithIntervale(); // синхронная операция BootReceiver.completeWakefulIntent(intent); } 

    Threat onStartCommand in the service is not needed and starting the service as usual is also not necessary. Enough work on schedule.
    ZZY I agree with the comment about the fact that once a minute to wake the phone, bad practice. On the other hand, fluffs can linger or be lost altogether. You should look for a middle ground (m. 5 minutes, maybe once an hour will be enough), based on the task.

    • Interval per minute is a requirement and not my trick :) I have almost completed the Firebase + Volley bundle - Flippy