前台20s后台200s不执行玩就报ANR异常。
没有界面在后台长期运行在主线程中的一个组件。
| Service | Thread |
| 可以配置执行在不同的进程中。 | CPU调度的最小单位。 |
| 任何有Context的地方都可以控制Service | 当Activity销毁后不再持有该Thread的引用,不管该子线程是一次任务还是循环任务都无法再控制。 |
| start方式 | bind方式 | |
| 使用场景 | 启动一个后台服务长期执行某个任务。 | 生命周期和Activity绑定。外部需要与服务通讯,调用服务中的方法。公开接口供客户端远程调用,绑定时才会执行。 |
| 生命周期 | onCreate→onStartCommand→onDestroy | onCreate→onBind→onUnbind→onDestroy |
| 多次开启 | 每次都执行onStartCommand | 无效果 |
| 多次关闭 | 抛异常? | 抛异常 |
所有和界面相关生命周期都没有。如果Service或者Activity是new出来的就是普通类不是组件了,这样调用里面的方法没意义。

系统会因为内存不足而销毁Service,是可以等到内存充足后再重建Service,并执行onStartCommand()。
| 返回值类型 | 说明 |
| return super.onStartCommand(intent, flags, startId) return Service.START_NOT_STICKY | 默认情况,被销毁后不会重建。 |
| return Service.START_STICKY | 被销毁后会重建。但是不再保存onStartCommand()中的形参intent。 |
| return Service.START_REDELIVER_INTENT | 被销毁后会重建。会将销毁钱最后一次传入onStartCommand()中的Intent保留。 |
- <service
- android:name=".MyService" //Service的类名
- android:label //Service的名字,若不设置,默认为Service类名
- android:icon //Service的图标
- android:permission //申明此Service的权限,有提供了该权限的应用才能控制或连接此服务
- android:process //表示该服务是否在另一个进程中运行(远程服务),不设置默认为本地服务;remote则设置成远程服务
- android:foregroundServiceType="location|camera|microphone" //在前台Service中获取定位/摄像头/麦克风权限需要配置(Android10引入定位,11引入摄像头麦克风)
- android:enabled="true" //是否默认启动,默认为 true
- android:exported="true" //该服务是否能够被其他应用程序所控制或连接 不设置默认此项为 true
- >
- <intent-filter android:priority="1000" /> //配置优先级,最大1000
- service>
- 长期后台运行(不会因为APP或者Activity销毁而停止,但服务进程在内存不足时会被回收),外部不能调用Service里的方法。
- 每调用一次startService(),onStartCommand()就会执行一次,但实际上每个 Service 只会存在一个实例。所以不管调用了多少次 startService(),只需调用一次 stopService() 或 stopSelf() ,Service就会停止。stopSelf() 是 Service 内部自己调用的。
- class MyService : Service() {
- //第一次创建的时候才调用
- override fun onCreate() { super.onCreate() }
- //每次启动的时候都会调用
- override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
- return super.onStartCommand(intent, flags, startId)
- }
- //销毁的时候调用
- override fun onDestroy() { super.onDestroy() }
- }
-
- Activity {
- //开启和关闭不要用同一个intent,当退出Activity后开启的intent就是null,关闭调用报错。
- //实际开发开启和注销服务都写在Activity的onStart()、onDestroy()里面就没有这个问题
- btn1.setOnClickListener {
- val intent = Intent(this, MyService::class.java)
- startService(intent) //启动服务
- }
- btn2.setOnClickListener {
- val intent = Intent(this, MyService::class.java)
- stopService(intent) 停止服务
- }
- }
- 生命周期和Activity同生共死,外部可以调用Service中的方法,可以和多个Activity绑定共享。
- 隐形的服务系统设置里面查不到,Activity死的时候Service也死了,不能长期在后台运行。bindService()绑定服务会调用onCreate() => onBind(),unbundService()解绑服务会调用onUnbind() => onDestroy()。绑定后再绑定无效果,解绑后再解绑抛异常,因此写到Activity的onCreate()和onDestroy()中。
- Binder是可以用作Service和Client之间通信,无论Service和Client是否在同一个进程内,Binder都可以完成Service和Client之间的通信。
- //抽取用于暴露Service中供外部调用的功能
- interface IFunction {
- fun callEat()
- fun callJump()
- }
-
- class MyService : Service() {
- //绑定时调用
- override fun onBind(intent: Intent): IBinder {
- return MyBinder() //返回代理人实例,供外部Client与Service通讯
- }
- //解绑时调用
- override fun onUnbind(intent: Intent?): Boolean {
- return super.onUnbind(intent)
- }
- //销毁的时候调用
- override fun onDestroy() {
- super.onDestroy()
- }
- //Service中自定义的函数
- fun eat() {}
- fun jump() {}
- //定义代理人,在代理人中提供调用Service的对应方法
- inner class MyBinder : Binder(), IFunction {
- override fun callEat() { eat() }
- override fun callJump() { jump() }
- }
- }
-
- Activity {
- private lateinit var function: IFunction
- private val connection = object : ServiceConnection {
- //绑定时调用
- override fun onServiceConnected(name: ComponentName, binder: IBinder) {
- //抽取成属性供别处调用
- function = binder as IFunction //转为抽取的接口对象来调用Service暴露的功能
- }
- //解绑时调用
- override fun onServiceDisconnected(name: ComponentName) {...}
- }
- btn1.setOnClickListener{
- val intent = Intent(this, MyService::class.java)
- bindService(intent, connection, Context.BIND_AUTO_CREATE) //绑定Service
- }
- btn2.setOnClickListener{
- val intent = Intent(this, MyService::class.java)
- unbindService(connection) //解绑Service
- }
- btn3.setOnClickListener{
- function.callJump() //就可以调用Service里的方法了
- function.callEat()
- }
- }
- 既长期在后台运行,又能调用 Service 里面的方法。
- 在 Activity 的 onCreate() 中 startService() 并 bindService(),顺序无所谓。
- 在 Activity 的 onDestroy() 中 unbindService(),根据情况在需要的地方stopService(),顺序无所谓两者都调用才会销毁服务。
- startService() 后,不管是否有 Activity 进行 bindService() 或 unbindService(),Service都在后台运行着,直到调用 stopService() 或 stopSelf() 才会关闭,或者系统资源不足时被杀死。
Aidl接口描述语言,专门用来解决调用远程服务的方式。
调用第三方支付中APP中的付款功能,要将支付信息传递过去:
①用隐式意图开启到对方Service
Intent intent = new Intent();
intent.setAction("cn.hugmua.demo.remote");
bindService(intent,conn,BIND_AUTO_CREATE);
②远程应用中,把暴露出来的接口Iservice.java改成Iservice.aidl,删除public权限修饰(public是包和包之间,而现在用于多个工程之间)
③远程应用中,自定义的MyBinder只继承Stub。在gen目录里生成了新的Iservice.java,里面的Stub帮我们继承了Binder和实现了Iservice
④本地应用中,创建和远程服务中相同包名,并把Iservice.aidl复制过来,gen目录下会自动生成相应报名文件夹,里面有Iservice.java
⑤本地应用中,在连接器ServiceConnection的onServiceConnected()中,调用Stub静态方法anInterface()将IBinder转换为Iservice
public void onServiceConnected(ComponentName name, IBinder service) {
iservice = Stub.anInterface(service);
}
⑥现在就可以用iservice对象调用远程服务里的方法了,要处理异常。
从Android 8.0开始,只有APP保持在前台可见状态的情况下 Service 才能保证稳定运行,一旦进入后台 Service 随时都有可能被系统回收,防止恶意APP长期在后台占用手机资源。因此需要 Service 能一直保持运行状态就可以使用前台Service。
- 前台Service在状态栏里会显示图标,下拉通知栏有显示通知。(这样APP就以另一种形式保持前台可见让用户清楚得知道什么APP占用着资源)
- 前台Service优先级较高,不会由于系统内存不足而被回收;后台Service优先级较低,当系统出现内存不足情况时,很有可能会被回收。
| 从Android 9.0系统开始,必须在 Manifest 中进行权限声明。 |
- override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
- //构建"点击通知后打开MainActivity"的Intent对象
- val myIntent = Intent(this, MainActivity::class.java)
- val pendingIntent = PendingIntent.getActivity(this, 0, myIntent, 0)
- //构建通知
- val notification = Notification.Builder(this, "") //获取构建器
- .setContentTitle("标题") //设置通知的标题
- .setContentText("内容") //设置通知的内容
- .setSmallIcon(R.mipmap.ic_launcher) //设置状态栏小图标
- .setLargeIcon(R.mipmap.ic_launcher) //设置通知栏大图标
- .setContentIntent(pendingIntent) //设置点击通知后的操作
- .build() //构建一个通知
- //让Service变成前台Service,并在系统的状态栏显示出来
- startForeground(1, notification) //参数一唯一标识停止的时候还要用,参数二通知
- return super.onStartCommand(intent, flags, startId)
- }
-
- override fun onDestroy() {
- super.onDestroy()
- stopForeground(1) //开启时设置的唯一标识
- }
Service默认运行在主线程,耗时操作需要开启子线程。Service一旦启动就会一直运行,直到调用 stopService()、stopSelf() 或被系统回收,我们可能会忘记调用。为了简单创建一个异步会自动停止的Service,可以使用IntentService。
- class MyService : Service() {
- override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
- thread {
- //耗时任务
- stopSelf() //停止Service
- }
- return super.onStartCommand(intent, flags, startId)
- }
- }
-
- class MyIntentService : IntentService("MyIntentService") { //传入的字符串随意,只在调试的时候有用
- override fun onHandleIntent(intent: Intent?) {
- //耗时任务
- }
- override fun onDestroy() {
- super.onDestroy()
- Log.d("MyIntentService", "有自动停止")
- }
- }