How to run a Jobscheduler or a Service every minute wihout stopping?

久未见 提交于 2019-12-08 07:53:23

问题


I'm doing an Android app that requires sending its location frequently, every 1 minute or 2 minutes at the most. For this, I use a JobSchedulerService. I've already managed to make it run more than once every 15 minutes on devices with Android N version by replacing the .setPeriodic() with a .setMinimumLatency(). The fact is that at the beginning it is executed periodically in the established time, but after a while it runs every 7 or 9 minutes approximately.

I have already included the application in the battery saving white list, but didn't work. Is there any way to execute it or a similar service every minute with no restrictions? Doesn't matter how much battery the app spends.

EDIT:

This is what I've tried:

ReceiverService:

public class ReceiverService extends WakefulBroadcastReceiver {

@Override
public void onReceive(Context ctx, Intent intent) {

    if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
        if (!isMyServiceRunning(ServiceBackground.class, ctx))
            startWakefulService(ctx, new Intent(ctx, ServiceBackground.class));

        new ServiceAlarmManager(ctx).register();
    }

}

private boolean isMyServiceRunning(Class<?> serviceClass,Context context) {
    ActivityManager manager = (ActivityManager)context. getSystemService(Context.ACTIVITY_SERVICE);
    for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if (serviceClass.getName().equals(service.service.getClassName())) {
            Log.i("Service already","running");
            return true;
        }
    }
    Log.i("Service not","running");
    return false;
}

}

The ServiceAlarmManager is exactly the same as @madking said.


回答1:


You can put your code that sends location in a Service and implement an AlarmManager that periodically checks if your Service is running and restarts it if the Service has been killed by OS. You'll have to implement the AlarmManager using a WakefulBroadcastReceiver.

ReceiverService.java

public class ReceiverService extends WakefulBroadcastReceiver {

@Override
public void onReceive(Context ctx, Intent intent) {

    if (!YourService.isRunning()) {
        startWakefulService(ctx, new Intent(ctx, YourService.class));
    }

    new ServiceAlarmManager(ctx).register();
}
}

ServiceAlarmManager.java

public class ServiceAlarmManager {

private Context ctx;
private static final int TIME_INTERVAL = 300 * 1000;

public ServiceAlarmManager(Context context) {
    ctx = context;
}

public void register() {

    Intent serviceRestarter = new Intent();
    serviceRestarter.setAction("someString");

    PendingIntent pendingIntentServiceRestarter = PendingIntent.getBroadcast(ctx, 0, serviceRestarter, 0);
    AlarmManager alarmManager = (AlarmManager) ctx.getSystemService(ctx.ALARM_SERVICE);
    Date now = new Date();
        alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, now.getTime() + TIME_INTERVAL, pendingIntentServiceRestarter);

}
}

Also register your BroadcastReceiver in your Manifest.xml file

<receiver android:name=".ReceiverService">
        <intent-filter>
            <action android:name="someString" />
        </intent-filter>
    </receiver>

The register() method does two things.

1- Issues a broadcast which is caught by WakefulBroadcastReceiver and restarts the Service if required

2- Sets the next alarm to be invoked to check if the Service has been killed.

This way the service keeps running even if the OS kills it and you'll be able to send location updates periodically.

Note: Though this practice is not recommended as your application will use more battery but you don't seem to care about it as I did not either as some business requirements don't leave us a choice.




回答2:


I tried this and it works: in the onCreate() of your activity you schedule an Alarm for every minute (setAlarm). Everytime the alarm is triggered, WakefulBroadcastReceiver is called, and that's where we launch our service(s):

private static long INTERVAL_ALARM = 1 * 60 * 1000;

public static void setAlarm(Context context) {
    long current_time = Calendar.getInstance().getTimeInMillis();
    Intent myAlarm = new Intent(context.getApplicationContext(), AlarmReceiver.class);
    PendingIntent recurringAlarm = PendingIntent.getBroadcast(context.getApplicationContext(), 0, myAlarm, PendingIntent.FLAG_CANCEL_CURRENT);
    AlarmManager alarms = (AlarmManager) context.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
    alarms.setRepeating(AlarmManager.RTC_WAKEUP, current_time, INTERVAL_ALARM, recurringAlarm);
} 

And in the receiver:

public class AlarmReceiver extends WakefulBroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
        Intent myService = new Intent(context, MyService.class);
        context.startService(myService);
    }

}

In your service, you should stopSeflf() in the end of your treatment.

Don't forget to register your BroadcastReceiver in your Manifest.xml file

NB: WakefulBroadcastReceiver is deprecated in API level 26.1.0. JobSchedulerService does the work



来源:https://stackoverflow.com/questions/47224219/how-to-run-a-jobscheduler-or-a-service-every-minute-wihout-stopping

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