消息定时推送是app里面常用的一个功能,但是如何能保证我们推送消息和监测时间的service常驻呢,可以用自定义广播接收器的方式,通过 监听接收系统的屏幕解锁广播通知的方式检查与保持service的正常运行。
下面我写下自己用到的方法:
自定义广播接收器LockScreenReceiver.kt类,下面是LockScreenReceiver代码,注意是kotlin语言哦:
/**
* Created by wjj on 2018/6/4.
* 接收系统的锁屏,解屏广播通知
*/
class LockScreenReceiver : BroadcastReceiver(){
private var TAG = "LockScreenReceiver"
override fun onReceive(context: Context?, intent: Intent?) {
var action = intent!!.action
if (action==Intent.ACTION_SCREEN_OFF){
Log.d(TAG,"屏幕关闭了")
}else if (action==Intent.ACTION_SCREEN_ON){
Log.d(TAG,"屏幕开启了111")
//通过监听屏幕SCREEN_ON和SCREEN_OFF这两个action。奇怪的是,这两个action只能通过代码的形式注册,才能被监听到,
// 使用AndroidManifest.xml 完全监听不到。查了一下,发现这是PowerManager那边在发这个广播的时候,做了限制,
// 限制只能有register到代码中的receiver才能接收, 这里告诉了我们监听开锁屏事件是不能静态注册广播监听的。
//那么我们怎么才能保证我的服务一直是启动状态呢?其实还有另一个Action是可以反映出用户正在使用手机的行为,每个用户在使用手机的时候,
// 首先按电源键将屏幕点亮,紧接着就是解锁。解锁动作通过 android.intent.action.USER_PRESENT 发送出来,
// 我们就能识别出该用户进入了home界面,也就能启动我们相应的服务了。该Action在AndroidManifest.xml中可以静态注册且监听得到的。
}else if (action==Intent.ACTION_USER_PRESENT){
Log.d(TAG,"屏幕开启了222")
//Intent.ACTION_USER_PRESENT会在手机解锁屏幕时调用发出,这个广播可以在静态注册的情况下被接收到,重启服务的操作可以写在这里面
initMyService(context)
}
}
//初始化系统消息推送服务
private fun initMyService(context: Context?) {
if (!ServiceUtils.isServiceRunning(context, "com.wj.compontents.service.MyService")) {
val intent = Intent(context, MyService::class.java)
context!!.startService(intent)
Log.d(TAG, "MyService没有运行")
} else {
Log.d(TAG, "MyService正在运行")
}
}
}
在清单文件AndroidManifest.xml文件中注册广播接收器:
<!-- 锁屏事件 -->
<receiver
android:process="system"
android:name=".compontents.receiver.LockScreenReceiver">
<intent-filter>
<action android:name="android.intent.action.SCREEN_OFF"/>
<action android:name="android.intent.action.SCREEN_ON"/>
<action android:name="android.intent.action.USER_PRESENT"/>
</intent-filter>
</receiver>
到此就ok了基本,可以跑起来测试下效果……
然后在这里附上我个人对服务常驻的一些经验总结:由于Android4.0以下和5.0以上进程杀死机制不一样,谷歌越来越禁止应用后台进程始终保活不被杀死,即使注册接受开机,解锁屏幕广播,应用没有开启之前也不允许接收到,也就无法通过监听系统的开机,解锁屏幕启动后台推送轮循服务进程,一些深度定制的ROM的手机厂家会在它们的清理逻辑,例如小米和魅族直接在用户或者系统杀死应用进程后直接把应用的STOPPED状态值重置为STOPPED则,这意味着再也无法接受到相应的系统广播除非再次启动一下应用清除掉STOPPED标识,除了尝试上面方法外,还使用了很多方法来保活进程,例如后台服务走销毁生命周期后自动在重新调用启动;调用手机系统电源管理对象在手机屏幕休眠时仍保持cpu运行,但无法保证应用进程被系统杀死后能再次唤醒;注册清单文件时给service尝试绑定系统进程,但需要诱骗用户给予系统通知权限,而且似乎属于是谷歌的一项未曾解决bug,后期可能会被禁止,所以不考虑采用;另外有些手机厂商把一些知名的app放入了自己的白名单中,保证了进程不死来提高用户体验(如微信、QQ、陌陌都在小米的白名单中)。如果从白名单中移除,他们终究还是和普通app一样躲避不了被杀的命运,所以进程不被杀死只能尽量争取!
以上写的是个人的一些开发中的经验与总结,不一定全对,如果您有更好的方法或者发现有不对的地方欢迎留言指正,探讨与交流!