使用服务首先想到的就是Service,然后在8.0上做兼容处理。

按理说做完以上可以正常功能,没问题,但是因需求原因,发现还是会出现异常:

  • android.app.RemoteServiceException

Context.startForegroundService() did not then call Service.startForeground()android.app.ActivityThread$H.handleMessage(ActivityThread.java:2204)

 

 

 

刚开始没有头绪,后来发现这个错误越来越多,但是仍然没有找到问题所在。因为直觉告诉是服务在8.0系统的兼容问题。但是明明已经做了这个兼容处理啊!!!

看看服务类:

 

class AlarmService: Service() {    private val MSG_TYPE_HANDLE_RESIDENT_NOTIFICATION = 0    private val FOREGROUND_SERVICE_ID = 1    private val mHandler: Handler = object : Handler() {        override fun handleMessage(msg: Message) {            super.handleMessage(msg)            if (msg == null) {                return            }            when(msg.what) {                MSG_TYPE_HANDLE_RESIDENT_NOTIFICATION -> {                    //刷新常驻通知栏                    NotificationUtil.showResidentNotification(CommonManager.getBaseContext())                    // 刷新小组件                    WidgetManager.refreshAllWidget(this@AlarmService)                    //定时发送通知广播,然后启动该service执行任务                    NotificationUtil.setAlertAlarm()                }                else -> {}            }        }    }    companion object {        @JvmStatic        fun startAlarmService(context: Context?) {            val intent = Intent()            intent.action = Intent.ACTION_VIEW            intent.setClass(context, AlarmService::class.java)            AppUtils.startForegroundServiceSafety(context, intent) //兼容8.0之前 之后启动服务        }    }    override fun onBind(intent: Intent?): IBinder? {        return null    }    override fun onCreate() {        super.onCreate()        Trace.e("onVisibleToUser", "启动服务: ${System.currentTimeMillis()}")        dealWithForegroundService()    }    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {        Trace.e("onVisibleToUser", "onStartCommand")        dealWithForegroundService()        val msg = mHandler.obtainMessage()        msg.what = MSG_TYPE_HANDLE_RESIDENT_NOTIFICATION        if (intent != null) {            msg.obj = intent.action        }        mHandler.sendMessage(msg)        return super.onStartCommand(intent, flags, startId)    }    /**     * 说明:处理8.0以上服务---8.0以后在后台启动服务会导致app崩溃,故启动方式需要兼容8.0,同时需要将服务变为前置     * 作者:耿保龙     * 添加时间:2020/6/30 14:48     * 修改人:耿保龙     * 修改时间:2020/6/30 14:48     */    private fun dealWithForegroundService() {        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {            val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager?            val channel = NotificationChannel("app_alarm_service", getString(R.string.app_name), NotificationManager.IMPORTANCE_MIN)            notificationManager?.createNotificationChannel(channel)            val notification = Notification.Builder(applicationContext, "app_alarm_service")                .setContentTitle(getString(R.string.app_name))                .setContentText("正在更新天气...")                .build()            Trace.e("onVisibleToUser", "变为前台服务")            startForeground(FOREGROUND_SERVICE_ID, notification) //可以保证兼容8.0在后台启动服务            stopForeground(true) //保证兼容后不让通知栏显示,即不让用户在通知栏看到“xxx正在运行 触摸即可了解详情或停止应用”        }    }    override fun onDestroy() {        super.onDestroy()    }}

 

其中,启动服务的方法

 

    @JvmStatic fun startForegroundServiceSafety(context: Context?, intent: Intent?) {        context?.runSafety {intent?.let {            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {                context.startForegroundService(it)            } else {                context.startService(it)            }        }}    }

是吧,明明已经处理了8.0的兼容问题,但是这个错依然频繁出现!!!

那就可能是:因为是在首页启动的服务,那么有可能是有的手机启动app比较卡,导致5s内没有回调startForeground,最终导致了崩溃。

偶然一次,在测试机魅族M1816上重现了该异常,启动到首页确实卡,也确实崩了。最后发现还有一个因素是:因为是定时启动该服务,执行操作,当我把时间设置为每2s执行一次时,那么势必会频繁启动该Service,启动了几次之后也出现了崩溃。但是在非8.0系统的手机上则不会崩溃。

结论:出现   android.app.RemoteServiceException的根本原因还是8.0系统中服务的兼容性。

那么现在说解决,发现通过寻常的Service无法彻底解决该问题,那怎么办呢?

最后找到了一种替代方案:使用   JobIntentService 替代 传统的Service。

经过验证:问题得到解决!!!

class NotifyAlarmService: JobIntentService() {    private val MSG_TYPE_HANDLE_RESIDENT_NOTIFICATION = 123    private val mHandler: Handler = object : Handler() {        override fun handleMessage(msg: Message) {            super.handleMessage(msg)            if (msg == null) {                return            }            when(msg.what) {                MSG_TYPE_HANDLE_RESIDENT_NOTIFICATION -> {                    //刷新常驻通知栏                    NotificationUtil.showResidentNotification(CommonManager.getBaseContext())                    // 刷新小组件                    WidgetManager.refreshAllWidget(this@NotifyAlarmService)                    //定时发送通知广播,然后启动该service执行任务                    NotificationUtil.setAlertAlarm()                }                else -> {}            }        }    }    companion object {        private const val JOB_ID = 1000        @JvmStatic        fun enqueueWork(context: Context?) {            val intent = Intent()            context?.let {                intent.setClass(context, NotifyAlarmService::class.java)                enqueueWork(context, NotifyAlarmService::class.java, JOB_ID, intent)            }        }    }    override fun onHandleWork(intent: Intent) {        Trace.e("NotifyAlarmService", "onHandleWork")        val msg = mHandler.obtainMessage()        msg.what = MSG_TYPE_HANDLE_RESIDENT_NOTIFICATION        if (intent != null) {            msg.obj = intent.action        }        mHandler.sendMessage(msg)    }}

这样,就不用再担心会出现8.0上对服务的兼容性问题了!!!

更多相关文章

  1. Android点击通知栏信息后返回正在运行的程序,而不是一个新Activit
  2. Android应用启动白屏问题
  3. Android(安卓)Looper(cpp)用法举例
  4. GLES2.0 on Android(安卓)emulator
  5. 【Android开发bug】Dropping event due to no window focus
  6. Android(安卓)4.2 原生系统有哪些方法实现全屏下隐藏导航栏?
  7. Android(安卓)Permission权限通知
  8. Android中文API(145) —— NotificationManager
  9. Android全屏显示(隐藏项目名和通知栏)

随机推荐

  1. AndroiManifest.xml文件中android属性
  2. Android Studio(The Official IDE for An
  3. android Notification 的使用
  4. android 有时候stroke不起作用
  5. android ListView 样式 item样式,条目样式
  6. Android音频可视化
  7. Android应用程序资源
  8. Android开机自启动
  9. 【转】android:windowSoftInputMode属性
  10. Android undefined reference to `stderr