Service是Android的四大组件之一,属于计算型组件,它的作用是提供需在后台长期运行的服务(比如复杂计算、音乐播放、下载等),特点是无用户界面、在后台运行、生命周期长
在Service的生命周期里,常用的有:
手动调用方法 | 作用 |
---|---|
startService() | 启动服务 |
stopService() | 关闭服务 |
bindService | 绑定服务 |
unbindService | 解绑服务 |
内部自动调用的方法 | 作用 |
---|---|
onCreate() | 创建服务 |
onStartCommand() | 开始服务 |
onDestroy() | 销毁服务 |
onBind() | 绑定服务 |
onUnbind() | 解绑服务 |
Service可以按照运行地点、运行类型、功能进行分类,具体如下:
这是最普通、最常用的后台服务Service
步骤1:新建子类继承Service类
需要重写父类的onCreate()、onStartCommand()、onDestroy()和onBind()方法
步骤2:构建用于启动Service的Intent对象
步骤3:调用startService()启动Service、调用stopService()停止服务
步骤4:在AndroidManifest.xml里注册Service
AndroidManifest里Service的常见属性说明:
属性 | 说明 | 备注 |
---|---|---|
android:name | Service的类名 | |
android:label | Service的名字 | 若不设置,默认为Service类名 |
android:icon | Service的图标 | |
android:permission | 申明此Service的权限 | 有提供了该权限的应用才能控制或连接此服务 |
android:process | 表示该服务是否在另一个进程中运行(远程服务) | 不设置默认为本地服务;remote则设置成远程服务 |
android:enabled | 系统默认启动 | true:Service将会默认被系统启动;不设置则默认为false |
android:exported | 该服务是否能够被其他应用程序所控制或连接 | 不设置默认此项为false |
这种Service增加了与Activity通信的功能,即使用绑定Service服务(Binder类、bindService()、onBind()、unbindService()、onUnbind())
前台Service和后台Service(普通)最大的区别就在于:
多个应用程序共享同一个后台服务(远程服务)
1.IPC:Intent-Process Communication,即跨进程通信
2.AIDL:Android Interface Definition Language,即Android接口定义语言;用于让某个Service与多个应用程序组件之间进行跨进程通信,从而可以实现多个应用程序共享同一个Service的功能
在多进程通信中,存在两个进程角色:服务器端、客户端
服务器端:
步骤1:新建定义AIDL文件,并声明该服务需要向客户端提供的接口
步骤2:在Service子类中实现AIDL中定义的接口方法,并定义生命周期的方法(onCreate、onBind)
步骤3:在AndroidManifest.xml中注册服务,声明为远程服务
客户端:
步骤1:拷贝服务端的AIDL文件到目录下
步骤2:使用Stub.asInterface接口获取服务器的Binder,根据需要调用服务提供的接口方法
步骤3:通过Intent指定服务端的服务名称和所在包,绑定远程Service
后台:后台任务运行完全不依赖UI,即使Activity被销毁/程序被关闭,只要进程还在,后台任务就可以继续运行
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//新建工作线程
new Thread(new Runnable() {
@Override
public void run() {
// 开始执行后台任务
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
class MyBinder extends Binder {
public void service_connect_Activity() {
//新建工作线程
new Thread(new Runnable() {
@Override
public void run() {
// 执行具体的下载任务
}
}).start();
}
}
多线程的应用在Android开发中是非常常见的,常用方法只要有:
IntentService是Android里的一个封装类,继承自四大组件之一的Service,它的作用是处理异步请求、实现多线程
线程任务需要按顺序、在后台执行
1.最常见的场景:离线下载
2.不符合多个数据同时请求的场景:所有的任务都在同一个Thread looper里执行
若启动IntentService多次,那么每个耗时操作都以队列的方式在IntentService的onHandleIntent回调方法中依次执行,执行完自动结束
@Override
public void onCreate() {
super.onCreate();
// 1. 通过实例化andlerThread新建线程 & 启动;故 使用IntentService时,不需额外新建线程
// HandlerThread继承自Thread,内部封装了 Looper
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
// 2. 获得工作线程的 Looper & 维护自己的工作队列
mServiceLooper = thread.getLooper();
// 3. 新建mServiceHandler & 绑定上述获得Looper
// 新建的Handler 属于工作线程 ->>分析1
mServiceHandler = new ServiceHandler(mServiceLooper);
}
/**
* 分析1:ServiceHandler源码分析
**/
private final class ServiceHandler extends Handler {
// 构造函数
public ServiceHandler(Looper looper) {
super(looper);
}
// IntentService的handleMessage()把接收的消息交给onHandleIntent()处理
@Override
public void handleMessage(Message msg) {
// onHandleIntent 方法在工作线程中执行
// onHandleIntent() = 抽象方法,使用时需重写 ->>分析2
onHandleIntent((Intent)msg.obj);
// 执行完调用 stopSelf() 结束服务
stopSelf(msg.arg1);
}
}
/**
* 分析2: onHandleIntent()源码分析
* onHandleIntent() = 抽象方法,使用时需重写
**/
@WorkerThread
protected abstract void onHandleIntent(Intent intent);
/**
* onStartCommand()源码分析
* onHandleIntent() = 抽象方法,使用时需重写
**/
public int onStartCommand(Intent intent, int flags, int startId) {
// 调用onStart()->>分析1
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
/**
* 分析1:onStart(intent, startId)
**/
public void onStart(Intent intent, int startId) {
// 1. 获得ServiceHandler消息的引用
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
// 2. 把 Intent参数 包装到 message 的 obj 发送消息中,
//这里的Intent = 启动服务时startService(Intent) 里传入的 Intent
msg.obj = intent;
// 3. 发送消息,即 添加到消息队列里
mServiceHandler.sendMessage(msg);
}
总上面的源码可以看出:IntentService本质上是Handler + HandlerThread
因此我们通过复写onHandlerIntent()、在里面根据Intent的不同进行不同的线程操作即可
1.工作任务队列是顺序执行的
2.不建议通过bindService()启动IntentService
即若一个任务正在IntentService中执行,此时你再发送1个新的任务请求,这个新的任务会一直等待直到前面一个任务执行完毕后才开始执行
原因:
原因:
// 在IntentService中,onBind()`默认返回null
@Override
public IBinder onBind(Intent intent) {
return null;
}
采用bindService()启动IntentService的生命周期如下:
onCreate() -> onBind() -> onUnbind() -> onDestory()
即并不会调用onStart()或onStartCommand(),故不会将消息发送到消息队列,那么onHandlerIntent()将不会回调,即无法实现多线程的操作
此时,就应该使用Service而不是IntentService