美文网首页
service基础

service基础

作者: 啦啦哇哈哈 | 来源:发表于2018-10-24 23:26 被阅读0次

这篇旨在复习service的基础知识,就是把之前在知乎上写的笔记差不多复习了一下,把文章搬运了过来
要点提炼

  • 一个类 extends Serivce 并在AM中注册<service>标签
  • 生命周期三个回调第一次创建onCreate() 每次启动onStartCommand 每次终止onDestroy
  • 在活动中可以构造intent +Context下的 startService + stopService来启动和终止服务,在Service中可以stopSelf自行终止服务
  • 活动和服务通信通过Binder对象,核心在于service中的onBind方法,需要在服务中建一个类extends Binder,里面加一些能够控制服务的方法,onBind方法返回这个类的对象
  • 在活动中通过实现ServiceConnection这个类中方法提供的参数获取上述的Binder对象,通过Binder对象来完成服务和活动之间的通信。
  • intent + bindService() + unbindService是活动和对应的服务绑定
  • 最后是前台服务IntentService

服务,让程序在后台运行,适合去执行不需要和用户交互但是要求长期运行的任务。服务的运行不依赖于任何用户界面,也不运行在独立的进程中,而是依赖于创建服务时所在的应用程序进程。使用服务需要用到我们Android多线程编程的一些知识。

定义服务

新建一个ServiceTest项目,New个service出来:

Exproted表示是否允许其他程序访问这个服务,Enabled表示是否启用这个服务。生成的代码是这样的:


里面自动生成了构造器,然后还有个onBind方法,这是Service中唯一一个抽象方法,我们后面会介绍。定义一个服务要处理一些事情,就需要重写一些方法:


这是常见的重写的几个方法。服务属于四大组件之一,我们还需要在AM中去注册一下,当然在new Service那一步里面,AS已经智能的完成了这一步:

启动和停止服务

启动和停止主要借助Intent实现。我们实践一下,修改ServiceTest项目,布局如下:


然后点击事件:


两个Intent,然后分别调用startServicestopService,这两个方法都是Context类的,这里我们可以直接调用,由活动来决定服务的开始与终止,而另外,也可以在MyService的任何地方使用stopSelf()方法,来让服务自行终止。为了能看到效果,我们在MyService里面重写方法,用Log.d打印一下方法执行了的结果:

运行如下:


Logcat界面:


依次点了start,start,start,stop,start。结果符合预期。

活动和服务进行通信

上面这个例子中,就是在活动里面startService了一下,启动服务的活动和服务之间没有多大的关系,如果想在活动中指挥服务去干什么,要借助Service类的onBind方法。

这里我们希望在MyService里面提供一个下载功能,并且在活动中决定何时开始下载,以及随时查看进度。修改MyService代码如下:


新建了一个内部类,继承自Binder,里面简单写了两个方法,模拟开始下载和获取进度。并且新建了这个类的实例,并且在onBind方法中返回这个实例。下面在布局里面新增两个按钮:

用于把活动绑定和解绑服务。绑定之后,活动就可以调用Binder提供的方法了。修改活动:



创建了ServiceConnection匿名类,重写了两个方法,从名字上也能看出来是绑定建立和绑定取消的时候会被调用的。onServiceConnected方法里面,向下转型得到了DownloadBinder实例,有这个实例之后,就可以通过它在活动中调用一些DownloadBinder的public方法,实现所谓的在活动中指挥服务,让活动和服务的联系紧密了一些。我们这里调用了两个方法。当然还没有完成绑定,在按钮点击事件里面,还是用Intent,调用了bindService方法,参数依次是intent,connection还有BIND_AUTO_CREATE,第三个参数是一个标志位,这个BIND_AUTO_CREATE表示活动和服务绑定之后自动创建服务,会使得服务中的onCreate方法执行,但是onStartCommand不会执行,解绑按钮中调用unbindService即可。

运行之后,先bind再unbind,并且查看logcat:


服务的生命周期

服务和活动一样,也有自己的生命周期,各个生命周期内涉及的回调方法有onCreate(),onStartCommand(),onBind()onDestroy()

startService方法调用之后,服务就会启动起来,回调onStartCommand方法,没有创建过的话,onCreate会被先行执行。当调用stopService或者stopSelf方法之后,onDestroy方法会被执行。每startService一次,都会执行一次onStartCommand,但是每个服务只会存在一个实例,最终只需要一次stop服务就会停止了。

另外的onBind方法,是在bindService方法执行之后调用,把onBind的返回结果交给匿名类的IBinder参数,就是上一节演示的那样。而如果第一次创建,onCreate方法会先执行,只要没有unbindService方法,服务就会一直运行。

而有一种情况,可能既startService了,又bindService了,又有当stopService(或stopSelf)和unbindService同时调用了,才会onDestroy

这就是服务的生命周期。

使用前台服务

服务几乎在后台运行,当系统内存不足时候,就可能回收掉正在后台运行的服务。但是如果想要服务一直保持运行状态,不因为内存不足被回收,就要使用前台服务。前台服务会有一个正在运行的图标一直显示在系统状态栏类似于通知的效果。现在用的这个华为运动大概就属于前台服务吧。

修改MyService如下:


几乎和通知那块没什么两样,但是最后不是使用NotificationManager将通知显示出来,而是调用startForeground方法,两个参数,第一个是id,第二个是构建出来的Notification对象。


这个通知划也划不掉。

使用IntentService

上面我们所有服务相关代码全部写在主线程中,如果处理耗时逻辑的话,就容易出现ANR(Application Not Responding)的情况。应该在子线程中处理这些事情。一般像这样写,比较标准的服务:


里面调用stopSelf是为了让在执行完任务之后让服务停止下来。

而Android同时还提供了一个IntentService简化这些操作。新建一个MyIntentService继承自IntentService:

我们重写了一下onHandleIntent方法,这个方法就是运行在子线程中的,就是在这个方法里面处理耗时逻辑的。我们打印了一下当前线程的id来验证这个确实是子线程。构造器里面调用了一下超类的有参数的构造器。最后onDestroy里面打印一下销毁执行了。然后按钮里面加一个启动MyIntentService的按钮:

修改活动代码:


启动还是用Intent,然后也不要忘了AM里面申请一下服务(其实如果用AS的New里面的intentService,会帮助我们自动申请,但是自动的会生成一些现在用不到的代码,所以就手动创建手动申请了):

可见并不是一个线程,同时onHandleIntent执行完毕之后还自动stop服务了。

相关文章

网友评论

      本文标题:service基础

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