我有一个应用程序,其功能A应该每分钟都在后台运行。功能A是应用程序应该连接到数据库,读取一些数据然后获取设备的当前位置并根据它们检查条件,如果条件为真,它应该向用户发送状态栏通知,以便用户点击通知,将显示应用的用户界面并发生一些事情
这个后台任务应该每分钟都运行一次,无论应用程序是否被使用,关闭,终止(例如facebook或Whatsapp向我们显示通知,无论它们是否在应用程序堆栈中)。
现在我搜索并发现Android提供 Job Scheduler ,后台服务, AlarmManager 和处理程序。
但是我读到的越多,这些陈述对我来说就越矛盾。
答案 0 :(得分:25)
我有一个应用程序,其功能A应该每分钟都在后台运行。
由于Doze模式(以及可能的应用待机状态,取决于应用的其余部分),数百万台Android设备(运行Android 6.0及更高版本)不会发生这种情况。
但是AlarmManager似乎是这个问题的一个很好的候选者,因为即使在系统重启后它们仍然存在
不,他们没有。您需要重新安排重启后使用AlarmManager
计划的所有警报。
警报管理器旨在用于必须在特定时间运行的任务
AlarmManager
支持重复选项。
这更像是我在阅读后在后台下载的任务,而不是用于我已经解释过的事情。
Service
对于您最终使用的解决方案至关重要。
与JobScheduler似乎不适用于必须永久完成的任务,但适用于满足特定约束(如空闲或无网络)的任务
JobScheduler
一样, AlarmManager
支持重复工作。
那么你建议使用我在第一部分中解释的任务中的哪一个(或其他如果存在的话)
不使用它们,因为一旦设备进入打盹模式,您将无法在Android 6.0+上每分钟运行一次,这将在屏幕关闭后一小时内完成。相反,要么重新设计应用程序,每天只需要几次背景工作,或者不打扰编写应用程序。
答案 1 :(得分:12)
如果你的minSdkVersion = 21,你可以使用Android 5.0中引入的现代JobScheduler
API。
还有https://github.com/firebase/firebase-jobdispatcher-android需要安装Google Play minSdkVersion = 9
但我建议使用此库https://github.com/evernote/android-job,根据Android版本,将使用JobScheduler
,GcmNetworkManager
或AlarmManager
。
使用这些API,您可以安排作业并运行描述任务的服务。
<强>更新强>
现在最好使用新的WorkManager
(docs)。 android-job
将很快弃用
答案 2 :(得分:6)
首先,JobService是一种服务。后台服务不明确,让我猜你的意思是在后台线程中运行的服务。作业服务在ui线程上运行,但您可以在其中创建异步任务对象以使其在后台运行。
从您的问题来看,JobService不是可行的方法。我建议的是:
您可以在该类的onDestroy方法中创建一个扩展IntentService(在后台线程上运行)的类,发送广播并使广播重新启动该服务。
@onDestroy(){
Intent broadcastIntent = new
Intent("com.example.myapp.serviceRestarted");
sendBroadcast(broadcastIntent);}
创建一个扩展广播接收器的类
public class RestartServiceReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context,
MyService.class));
}
}
<receiver android:name=".RestartServiceReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="com.example.myapp.serviceRestarted" /> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver>
启动权限是为了在系统完成启动后调用接收器,一旦调用接收器,将再次调用该服务。
答案 3 :(得分:2)
根据this 以及下面评论1中的其他链接
您应该使用AlarmManager完成任务。
如果您需要设置在Doze中触发的警报,请使用:
setAndAllowWhileIdle() or setExactAndAllowWhileIdle().
有关在后台执行操作的不同方法的完整易懂理解,请阅读: https://www.bignerdranch.com/blog/choosing-the-right-background-scheduler-in-android/
祝你好运!
答案 4 :(得分:1)
在以前的Android版本中,人们使用Handler或后台服务来实现此目的。过了一会儿,他们宣布了警报管理员课程,用于永久性的预定作品。
Whatsapp,脸书或一些社交媒体应用程序大多使用谷歌云消息传递通知目的,这对你没用。
我建议你使用报警管理器。在KitKat版本(4.2)之后,操作系统会阻止后台处理程序以更好地使用电池。
后台服务主要用于图像上传或一些具有结束时间的繁重过程。当您在Whatsapp上向朋友发送视频时,后台进程启动并将视频上传到后端服务器。
我不确定JobScheduler api是否支持旧版本的支持,但它与Alarm Manager一样好。
答案 5 :(得分:0)
你可以通过使用service来做到这一点,返回start_sticky in“START_STICKY告诉操作系统在有足够内存后重新创建服务并再次使用null intent调用onStartCommand()。START_NOT_STICKY告诉操作系统不要重新创建服务还有第三个代码START_REDELIVER_INTENT告诉操作系统重新创建服务并将相同的意图重新发送到onStartCommand()“
并设置一个周期为1分钟的TIMER并执行您的代码。
如果您想在用户强制停止时重新启动该服务,您可以“执行以前的答案”
您可以在该类的onDestroy方法中创建一个扩展IntentService(在后台线程上运行)的类,发送广播并使广播重新启动该服务。
@onDestroy(){
Intent broadcastIntent = new Intent("com.example.myapp.serviceRestarted");
sendBroadcast(broadcastIntent);
}
创建一个扩展广播接收器的类
public class RestartServiceReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context, MyService.class));
}
}
在您的清单中,注册您的服务和接收者
<receiver
android:name=".RestartServiceReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.myapp.serviceRestarted" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
此外,您可以使用AlarmManager,如果您需要设置在Doze中触发的闹钟,请使用:
setAndAllowWhileIdle()或setExactAndAllowWhileIdle()。
将其设置为“当前时间为秒+ 60秒”,以便您在下一分钟进行设置。
并执行您的代码,最后在下一分钟重置AlarmManager。
此外,您可以在重启设备后启动服务或AlarmManager 只需在“RECEIVE_BOOT_COMPLETED”
时使用brodcastReciever并提出此权限:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
答案 6 :(得分:-1)
在Lollipop之上,即API版本21,您可以使用JobScheduler
来安排JobService
。要每分钟重复一次作业,您必须将作业的最小延迟设置为60 * 1000毫秒,以安排每次作业完成的时间。
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class MyJobService extends JobService {
boolean isWorking = false;
boolean jobCancelled = false;
@Override
public boolean onStartJob(JobParameters params) {
Log.d("_____TAG_____", "MyJobService started!");
isWorking = true;
doWork(params);
return isWorking;
}
private void doWork(JobParameters params) {
if (jobCancelled)
return;
//Create a new thread here and do your work in it.
//Remember, job service runs in main thread
Log.d("_____TAG_____", "MyJobService finished!");
isWorking = false;
boolean needsReschedule = false;
jobFinished(params, needsReschedule);
scheduleRefresh();
}
@Override
public boolean onStopJob(JobParameters params) {
Log.d("_____TAG_____", "MyJobService cancelled before being completed.");
jobCancelled = true;
boolean needsReschedule = isWorking;
jobFinished(params, needsReschedule);
return needsReschedule;
}
private void scheduleRefresh() {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
ComponentName componentName = new ComponentName(getApplicationContext(), MyJobService.class);
JobInfo.Builder builder = new JobInfo.Builder(5, componentName);
builder.setMinimumLatency(60*1000); //1 minute
JobInfo jobInfo = builder.build();
JobScheduler jobScheduler = (JobScheduler)getApplicationContext().getSystemService(JOB_SCHEDULER_SERVICE);
int resultCode = jobScheduler.schedule(jobInfo);
if (resultCode == JobScheduler.RESULT_SUCCESS) {
Log.d("_____TAG_____", "MyJobService scheduled!");
} else {
Log.d("_____TAG_____", "MyJobService not scheduled");
}
}
}
}
您可以在任何喜欢的地方编写通用功能来首次安排作业-
public void scheduleMyJobService() {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
ComponentName componentName = new ComponentName(context, MyJobService.class);
JobInfo.Builder builder = new JobInfo.Builder(5, componentName);
builder.setMinimumLatency(60*1000);
JobInfo jobInfo = builder.build();
JobScheduler jobScheduler = (JobScheduler) context.getSystemService(JOB_SCHEDULER_SERVICE);
int resultCode = jobScheduler.schedule(jobInfo);
if (resultCode == JobScheduler.RESULT_SUCCESS) {
Log.d("_____TAG_____", "MyJobService scheduled!");
} else {
Log.d("_____TAG_____", "MyJobService not scheduled");
}
}
}