如何判断 App 处在后台?
满足以下任一条件的 APP 都属于在前台,Service 运行不受任何限制。除了下面列出的几种情况,那就是处于后台的 case 。
-
App 存在一个可见的 Activity,Activity 处于 started 或者 paused 或者 resume阶段;
-
App 中有一个前台 Service【即主动调用过
startForeground(int id, Notification notification)
的 Service】; -
app 被另一个前台 App 通过 Service、Content Provider 绑定或者连接
IME 输入法 APP,被系统的前台进程绑定【或者我们 APP 中的一个 Service,被其他第三方 APP 绑定,当第三方 APP 处在前台时,那么我们的 APP 也是处在前台的。】
-
Wallpaper service
-
Notification listener
-
Voice or text service
APP 存在常驻通知栏时,是否属于前台 APP?
只有通过 Service.startForeground(int id, Notification notification)
启动的通知栏,才能让 App 成为前台 APP。
再次强调,通过
NotificationManager.notify(int id, notification)
显示的普通通知,不会让 App 成为前台 APP,也不会让进程成为前台进程。必须通过Service.startForeground(int id, Notification notification)
方法现实的通知栏才有用。
Android O(8.0) 以上系统对 Service 增加了哪些限制?
Android O: APP 的
targetSdkVersion
配置大于等于26
当 APP 处于空闲期时,将会有如下两个限制:
- 主动调用
Context.startService()
将引发 crash。崩溃日志,如下:
java.lang.IllegalStateException: Not allowed to start service Intent { cmp=com.compat.test/com.test.Service4 }: app is in background uid UidRecord{a0d4e51 u0a84 CEM bg:+1m2s21ms idle procs:1 seq(0,0,0)}
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1505)
at android.app.ContextImpl.startService(ContextImpl.java:1461)
at android.content.ContextWrapper.startService(ContextWrapper.java:644)
at com.test.MainActivityV2$8.run(MainActivityV2.java:153)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
- 对于普通的 Service,App 进入空闲期后,系统将会立即停止并回收该服务
被回收就和我们自己主动调用
Context.stopService()
一样。 Service 将会被执行onDestory()
生命周期方法。
我们常说 App 进入空闲期,请问什么是空闲期?
首先请切记 App处在后台,并不等于处在空闲!!!
例如:Model PixelXL 手机, android 8.0.0系统,在 APP 进入后台状态,并保持处于 后台状态 1分钟后,才进入空闲期。APP从开始处于后台,到正式进入 空闲期 的这1分钟期间,App 可以随意
startService
是不会抛出异常的。App内的 Service 也不会被系统主动回收。在这 1分钟 期间,用户如果打开 APP,将 APP 置为前台,那么下次进入后台后需要重新计时,重新进入后台保持1分钟才会进入空闲期。
那么问题来了,怎么突破 Android O 以上系统对 Service 的限制呢?
1,App 处于空闲期时,如何启动一个 Service?
-
利用
JobService
,但是JobService
存在诸多限制,详情请查阅官方文档 -
以
bind
的方式启动 Service,这种方式启动 Service,将不受系统限制。
activity.getApplication().bindService(intent, connection, Service.BIND_AUTO_CREATE);
2,在 App 进入空闲期时,如何让普通的 Service 不被立即 stop?
普通的Service,在App进入空闲期时,将会被系统回收。那我们就思考什么是不普通的 Service???
Application.bindService()
绑定的 Service。 对你没看错,一定要是 Application
对象绑定上的 Service 才不会被 Stop。 一定要是 Application 对象 bindService()
。
// 如果是仅仅是被 Activity 对象绑定的话,APP 进入空闲期后,Service 依然都会被 stop。
Intent in = new Intent(MainActivityV2.this, Service4.class);
activity.getApplication().bindService(intent, connection, Service.BIND_AUTO_CREATE);
网友评论