Android-Service详解
Service是安卓的四大组件之一,在我们的日常开发中经常会使用到,例如执行一些后台操作,播放音乐、下载等等。
接下来我们就从一个简单的Service的使用开始,一步一步的深入介绍Service
Service简单使用
创建一个Activity,在Activity中设置两个按钮,用于启动、关闭Service,而在Service中只是打印一些生命周期的Log,并不去做什么事。
MainActivity
1 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { |
activity_main
1 |
|
MyService
1 | public class MyService extends Service { |
最后别忘了在AndroidManifest中注册Service
使用一个Service的步骤
- 创建一个类,继承Service
- 在AndroidMainfest中注册Service
- 在Activity中使用
startService
启动Service
注意我这里使用的是显示启动Service,如果要隐式启动Service,则需要在Intent中指定包名和action,步骤如下
1 | intent = new Intent(); |
不允许直接使用action去启动Service是从Android 5开始,即Android Lollipop
这时我们通过点击启动服务的按钮即可打开Service,看到打印的日志。
如果想要停止服务,则可以使用stopService()
传入Intent即可,注意,开启和结束Service的Intent必须为同一个Intent
Service绑定
上面的开启服务方式和调用startService
的Activity一点关系都没有,使用startService
只是告诉Service一声你可以启动了。如果想要将Activity和Service进行关联,则需要使用Context.bindService(Intent intent, ServiceConnection conn, int flags)
- 第一个参数的为传入的Intent
- 第二个参数为connect的状态回调
- 第三个参数为绑定关系
使用bindService
1 | bindService(intent, serviceConnection, BIND_AUTO_CREATE); |
intent和上面的一样,只不过这里我们需要去定义一下第二个参数
1 | ServiceConnection serviceConnection = new ServiceConnection() { |
实现了一个匿名内部类,该内部类中有两个必须实现的函数,也是非常重要的函数,即onServiceConnected
与onServiceDisconnected
onServiceConnected
表示当Activity与Service建立绑定成功时候的回调函数onServiceDisconnected
表示当Activity与Service断开连接时候的回调函数
onServiceConnected
方法有一个非常重要的参数IBinder service
,这个参数是绑定成功后Service返回的数据,还记不记得我们在Service中必须重写的方法
1 | public IBinder onBind(Intent intent) { |
IBinder service
参数就是接受来自onBind
的返回信息
如果想要返回消息,则需要创建一个类,继承自Binder
1 | // Service文件中 |
连接成功后即可在serviceConnection
中的onServiceConnected
中执行addPlus
方法
这里需要注意一下:如果在Service中的onBind方法中没有返回任何信息,即null,那么回调方法
onServiceConnected
与onServiceDisconnected
就不会执行,即使Service与Activity绑定成功了也不会执行
第三个参数flags,他有一个特殊的值,Context.BIND_AUTO_CREATE
。这个值特殊的地方就在于当我们绑定Service时,如果Service还未开启,bindService
就会开启Service,注意,这时会执行Service的全部与新建相关的生命周期函数
解绑服务只需使用unbindService
即可,参数传入与bindService
同一定义的ServiceConnectiong
Service的生命周期
Service的生命周期主要有onCreate
、onStartCommand
、onDestroy
当我们第一次启动Service的时候,会先执行onCreate
-> onStartCommand
当我们一直在执行startService
时,onCreate
只会执行一次,而onStartCommand
会每次都执行。
当我们使用bindService
的时候,onCreate
和onStartCommand
都不会执行(如果指定了BIND_AUTO_CREATE时且没有创建Service则会都执行)
最后我们使用stopService
的时候,会执行onDestroy
方法
如果我们在开启服务后,又使用
bindService
绑定Service,这时我们再关闭服务(stopService
),可以看到onDestroy
是不会执行的(即Service不会关闭),只有当前服务的所有绑定都解绑了(所有的绑定执行了unbindService
),然后使用stopService
才会销毁Service
跨进程Service
Service可以单独放在一个进程之中,只需要在AndroidMainfest文件中指定android:process
即可
1 | <application> |
可以在另一个进程的Activity中开启其他进程的Service,还是使用startService
即可,关闭也可以使用stopService
。
如果使用bindService
绑定其他进程的Service,这就涉及到唤醒Service了,需要使用隐式启动Service,显示启动无法获取到类的字节码信息(也就无法传入Intent)。
1 | intent = new Intent(); |
此时如果想要使用binder进行通信,可以使用Android的跨进程通信aidl,创建一个aidl文件
1 | package com.sui.mutiprocessapplication; |
有以下几个注意点:
- interface 前不要加public
- 函数的返回值前也不要加访问限制修饰符
Android Studio中将项目重新rebuild即可(Build -> Rebuild Project),即可生成对应的接口文件
一切准备就绪了,下面我们可以在Service的onBind
方法中返回实例化自定义aidl接口的类了
1 | public iBinder onBind(Intent intent) { |
在Activity中的ServiceConnect
中调用addPlus
1 | ServiceConnect connect = new ServiceConnection() { |
以上我们就完成了一次跨进程的Activity与Service之间的通信。
关于Service的一些问题
1.Service与Thread有什么区别?
在Service中不要进行一些耗时的操作,Service如果没有单独的开启一个进程,那么它是运行在主线程中的,即UI线程,执行耗时的操作可能会引发ANR,引入Service的目的是为了执行一些后台的操作,例如下载播放音乐等。如果在Service中执行耗时的操作,应该在其中开启一个线程。
关于Service的使用会在以后的操作过程中去慢慢更新,当前时间2021年1月27日