【问题标题】:How to run a Jobscheduler or a Service every minute wihout stopping?如何在不停止的情况下每分钟运行 Jobscheduler 或 Service?
【发布时间】:2017-11-10 13:45:55
【问题描述】:

我正在做一个需要频繁发送其位置的 Android 应用,最多每 1 分钟或 2 分钟发送一次。为此,我使用JobSchedulerService。通过将.setPeriodic() 替换为.setMinimumLatency(),我已经设法让它在Android N version 的设备上每15 分钟运行一次以上。事实是,一开始它会在规定的时间内定期执行,但一段时间后它大约每 7 或 9 分钟运行一次。

我已经将该应用程序包含在省电白名单中,但没有工作。有没有什么方法可以不受限制地每分钟执行一次或类似的服务?与应用消耗多少电量无关。

编辑

这是我尝试过的:

接收服务:

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;
}

}

ServiceAlarmManager和@madking说的一模一样。

【问题讨论】:

  • 这是非常糟糕的做法。请让设备休眠。
  • 你想要的都是不可能的
  • 这不可能,我不在乎这是不是一个糟糕的做法,因为设备会充电,优先级是每分钟发送一次位置,而不是电池
  • 也许你没有注意到谷歌是如何对应用程序的功能以及每次更新的频率施加更多限制的。但是请告诉我该怎么做,因为你似乎知道一些我不知道的事情
  • 我当然不是专家,我从中了解到新的限制是针对 Android O 的,对吧?我认为它必须是一种方法,例如前台服务或其他东西,但我不知道......

标签: android service periodic-task


【解决方案1】:

您可以将发送位置的代码放在Service 中并实现AlarmManager,它会定期检查您的Service 是否正在运行,如果Service 已被操作系统杀死,则重新启动它。您必须使用WakefulBroadcastReceiver 来实现AlarmManager

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);

}
}

同时在您的Manifest.xml 文件中注册您的BroadcastReceiver

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

register() 方法做了两件事。

1- 发出被WakefulBroadcastReceiver 捕获的广播,并在需要时重新启动Service

2- 设置要调用的下一个警报以检查 Service 是否已被杀死。

这样,即使操作系统将其杀死,该服务也会继续运行,并且您将能够定期发送位置更新。

注意:虽然不推荐这种做法,因为您的应用程序会使用更多电池,但您似乎并不关心它,因为我也不关心它,因为某些业务需求不会让我们选择。

【讨论】:

  • 感谢您的回答!我正在尝试实现您的代码,但我不知道.isRunning(),它是MyService.class 内部的Getter 吗?
  • @smartgg 不,您必须在此问题的第一个答案中实现类似的操作。 stackoverflow.com/questions/17588910/…
  • 所以检查LocationServiceServiceAlarmManager 是两个不同的类,对吧?
  • 我试图实现你的代码,我也把它放在开机启动。我重新启动并启动了,但只有一次:/
  • @smartgg 抱歉,因为是周末,所以回复晚了;)是的,他们是两个不同的班级。检查位置的Service 应从IntentService 扩展。您的第二条评论相当不清楚,但它有效,除此之外没有其他任何东西对我有用。也许你可以分享一些代码
【解决方案2】:

我试过这个并且它有效:在您的活动的 onCreate() 中,您为每分钟安排一个警报 (setAlarm)。每次触发警报时,都会调用 WakefulBroadcastReceiver,这就是我们启动服务的地方:

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);
} 

在接收器中:

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

}

在您的服务中,您应该在治疗结束时停止Seflf()。

别忘了在你的 Manifest.xml 文件中注册你的 BroadcastReceiver

注意:WakefulBroadcastReceiver 在 API 级别 26.1.0 中已弃用。 JobSchedulerService 完成工作

【讨论】:

    猜你喜欢
    • 2011-02-09
    • 1970-01-01
    • 2014-05-31
    • 1970-01-01
    • 2013-09-22
    • 1970-01-01
    • 1970-01-01
    • 2013-06-03
    • 1970-01-01
    相关资源
    最近更新 更多