美文网首页android相关Android应用开发那些事
Android 8.0之后如何正确使用Service

Android 8.0之后如何正确使用Service

作者: ImWiki | 来源:发表于2019-11-05 00:47 被阅读0次

    这篇文章简单介绍Service的一些使用注意事项,可以作为参考。

    何时使用Thread、何时使用Service

    Service是运行在主线程的,如果我们需要执行耗时操作,也是在Service创建Thread执行。所以我们需要明确一点,Thread和Service不是同一级别的类,Service和Activity才是同一级别的组件,所以这里讨论是应该是Thread应该是在Activity创建还是Service创建的问题。

    1. 如果耗时操作无法在当前Activity生命周期执行完成的任务就需要在Service执行,比如异步下载等。
    2. 需要长时间在后台运行,跟随APP生命周期的任务需要在Service执行,比如Socket长连接。

    有的人看到这里可能心中有个疑问,创建一个单例模式或者直接new Thread()来执行任务不也是可以实现吗,为何还要创建Service?

    确实是如此,如果我们直接new Thread()下载文件,确实是非常方便,假设下载的内容非常的大,可能需要几分钟才能下载完毕,比如下载电影,用户可能无法一直停留在APP,需要退到后台(锁屏、回到桌面或切换到其他APP),如果不使用Service,线程极有可能由于后台管控被暂停了。这个使用必须需要某种手段提高APP的等级,让系统继续为APP分配CPU资源,Service就显得尤为重要。

    什么是前台服务,什么是后台服务?

    在Android 8.0 推出了新的启动服务方法startForegroundService,不再允许开发者在后台通过startService启动服务,那么问题来了,什么情景下才是后台?

    什么是后台?

    当前APP的Activity离开手机屏幕(锁屏、回到桌面、切换到其他APP)超过60秒。

    什么是前台服务

    Android 8.0新增了startForegroundService方法,用于启动前台服务,前台服务是指带有通知栏的服务,如果我们使用startForegroundService启动服务,那么必须在5秒内调用startForeground()显示一个通知栏,否则就会报错,比如通知栏显示音乐播放器、下载进度。

    Android 8.0后是否必须使用 startForegroundService

    虽然Android 8.0之后新增了startForegroundService方法,但是startService还是可以正常使用。

    实际的案例和线上异常统计,部分Android 8.0手机的startService存在缺陷,虽然APP在前台但是还是会报出Not allowed to start service Intent异常,Google Pixel 就可以重现该问题。

    SDK中提供的常用服务基类

    Service

    Service是所有服务的基类,早期我们通常都是继承该类实现服务,如果使用该类,我们需要对Service的生命周期进行管理,在合适的地方停止Service。

    IntentService

    继承于Service,通过源码可以看到,是在Service的基础上增加了Handler、Looper、HandlerThread的支持,我们只需要重写onHandleIntent(Intent intent)实现异步任务,这个方法已经是非UI线程,可以执行耗时操作,一旦这个方法执行完毕,就会立刻执行stopSelf()停止服务,无需手动停止服务。

    但是在Android 8.0增加了后台服务限制,并提供了JobScheduler的支持,推荐使用JobIntentService代替IntentService。

    JobService

    继承于Service,通过源码可以看到,是在Service的基础上增加了JobScheduler的支持,可以非常简单实现多种网络状态的监控。

    JobIntentService

    继承于Service,带有IntentService和JobService的特性。

    LifecycleService

    继承于Service,增加了Lifecycle的支持,可以非常方便我们使用LiveData等。

    异常情况

    异常一
    java.lang.IllegalStateException: Not allowed to start service Intent { cmp=com.xx.xx/.xxxService }: app is in background uid UidRecord{4dbde56 u0a86 LAST bg:+1m13s953ms idle change:idle procs:1 seq(0,0,0)}
    

    该问题是由于APP在后台调用了startService启动服务导致异常,第一检查APP是否存在后台启动服务的情况,如果存在尽量使用使用startForegroundService启动前台服务(带有通知栏的服务),也可以使用JobService来解决服务问题。

    异常二
    android.app.RemoteServiceException
    Context.startForegroundService() did not then call Service.startForeground()
    

    这个是由于使用startForegroundService启动前台服务,但是没有在5秒内调用startForeground显示通知。

    异常三
    java.lang.SecurityException
    
    Unable to start service Intent { cmp=xx.xx.xx/.XXXService }: Unable to launch app xx.xx.xx/10093 for service Intent { cmp=cmp=xx.xx.xx/.XXXService }: user 0 is restricted
    

    如果这个错误只是在部分的小众手机出现,那么极有可能是由于部分手机厂商修改了Android的源码,增加了安全控制,比如禁止在Application初始化期间startService。

    相关文章

      网友评论

        本文标题:Android 8.0之后如何正确使用Service

        本文链接:https://www.haomeiwen.com/subject/wuwjbctx.html