今天我们介绍一下Android四大组件之一的Service。
Android的四大组件之一,是Android的一种机制,被设计来的目录是为了处理一些后台数据。通常情况下它是运行在主线程的,所以不要直接在service里面做耗时操作。耗时任务同样需要使用thread来处理。
Service分类:我们通过service运行的地方可以分为本地和远程服务。
本地服务:使用频率比较多,依附于主进程,可以节约一些资源。使用比较简单。缺点就是主进程结束之后也会跟着结束。
远程服务:很少使用,会单独开启一个进程。因此主进程结束后并不会对它有影响。缺点是使用相对复杂。主要是提供一些系统服务。
因为远程服务比较复杂,今天先将本地服务的用法,后面一章再专门讲远程服务。
我们先来看看官方给出的Service的生命周期图:
可以看到它的生命周期会根据我们启动方式分2种情况,startService和bindService。那么我们就来分别看看这2种方式有什么区别
再来看看生命周期,先看看startService:
首先创建一个Service,直接继承Service即可
MyService
class MyService : Service() { override fun onCreate() { super.onCreate() Log.d("ZLog MyService", "onCreate: ") } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { Log.d("ZLog MyService", "onStartCommand: startId:$startId") return super.onStartCommand(intent, flags, startId) } override fun onStart(intent: Intent?, startId: Int) { super.onStart(intent, startId) Log.d("ZLog MyService", "onStart: startId:$startId") } override fun onBind(intent: Intent): IBinder { Log.d("ZLog MyService", "onBind: $intent") return MyBinder() } override fun onUnbind(intent: Intent?): Boolean { Log.d("ZLog MyService", "onUnbind: ") return super.onUnbind(intent) } override fun onDestroy() { super.onDestroy() Log.d("ZLog MyService", "onDestroy: ") } private class MyBinder : Binder() { } }Manifest.xml配置
<service android:name=".MyService" android:enabled="true" />activity中启动服务的代码:
acMainBtStart.setOnClickListener { startService(myServiceIntent) } acMainBtStop.setOnClickListener { stopService(myServiceIntent) }界面就2个按钮,一个开始,一个停止
按下启动服务的按钮后按照官方的流程打印了,其中的onStart方法现在文档提示已经过时不推荐使用了。
这个方法是以前启动时会调用的方法。
那么如果我们现在反复的按下启动服务会怎么样呢?
大家可以看到,我又点击了3次,看到onCreate方法并没有重复的打印,只是onStartCommand在重复的调用,并且startId在递增,说明我们的Service并没有重复的创建,类似单例模式,只是每次启动系统会给我们一个计数器。
现在按下停止服务:
可以看到只有一个onDestroy被调用。这个时候再按下停止是没有任何反应了。意思是我们可以多次的调用启动同一个service,只会创建一个。停止服务只需要调用一次就可以了。
下面我们来看一下bindService的流程:
启动服务的activity:
private lateinit var myServiceIntent: Intent override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) myServiceIntent = Intent(this, MyService::class.java) acMainBtStart.setOnClickListener { bindService(myServiceIntent, conn, Context.BIND_AUTO_CREATE) } acMainBtStop.setOnClickListener { unbindService(conn) } } private val conn = object : ServiceConnection { override fun onServiceDisconnected(name: ComponentName?) { Log.d("ZLog MainActivity", "onServiceDisconnected: $name") } override fun onServiceConnected(name: ComponentName?, service: IBinder?) { Log.d("ZLog MainActivity", "onServiceConnected name:$name service:$service") } }Service不用修改,来看看运行的效果:
我们启动之后打印了onCreate和onBind,还记得刚刚说bindService的特点就是可以拿到一个Ibinder,就是在onBind这个方法中返回的。
override fun onBind(intent: Intent): IBinder { Log.d("ZLog MyService", "onBind: $intent") return MyBinder() }我们返回了一个MyBinder,在这里定义了一个内部类:
private class MyBinder : Binder() { }目前这里没有任何方法,它就是我们可以在activity中和服务端通讯的媒介了。
它继承自Binder,这个是系统提供的一个Ibinder子类,内部 已经帮我们实现了很多方法。所以我们直接继承它就好了。那么我们在哪里获取这个Binder呢?
在activity中我们调用bindService方法的时候,第二个参数是一个ServiceConnection,这个接口有2个方法,看名字就知道一个是和服务连接上的时候被调用的(onServiceConnected),一个是连接被断开的时候调用的(onServiceDisconected)。onServiceConnected的第二个参数是Ibinder,就是我们Service中onBind返回的接口。所以我们在这里就可以通过这个Ibinder强转成MyBinder类,从而实现和服务通讯的操作。
我们同样试试反复的点击bindService看看
会发现点击之后没有任何方法被回调,所以我们的bindService只能调用一次。
再来看看unbindService:
可以看到首先调用了onUnbind,然后onDestroy被调用。注意:这里在activity中ServiceConnection中的onServiceDisconnected并没有被调用,因为我们手动刁永刚unbindService的时候是属于主动断开,并不会调用onServiceDisconnected,onServiceDisconnected方法是在服务如果被意外杀掉的时候才会被调用。
官方文档的意思是只有到启动service的进程已经崩溃或被杀死时才会调用到。
好了,到这里service的一些基本用法就差不多介绍完了。后面一章我们重点讲解远程Service和AIDL相关内容。