1. 基本使用
1.1 什么是IntentService
IntentService是继承于Service并处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统Service一样,同时,当任务执行完后,IntentService会自动停止,而不需要我们去手动控制。另外,可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。
所有请求都在一个单线程中,不会阻塞应用程序的主线程(UI Thread),同一时间只处理一个请求。
1.2 IntentService 的好处
- 自动开启线程处理耗时任务.
- 操作完成时自动销毁Service.
1.3 基本使用
- 创建
IntentService
的子类.
/**
* @author : Brian
*/
public class MyIntentService extends IntentService {
private static final String TAG = "MyIntentService";
/**
* 默认构造
*/
public MyIntentService(){
this("MyIntentService");
}
/**
* 父类构造方法
*/
public MyIntentService(String name) {
super(name);
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
Log.d(TAG, "onHandleIntent: ");
String opType = intent.getExtras().getString("param");
// 分辨任务
Log.d(TAG, "任务 : " + opType);
// 延时 3s
SystemClock.sleep(3 * 1000);
}
/**
* Unless you provide binding for your service,
* you don't need to implement this method,
* because the default implementation returns null.
*/
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind: ");
return super.onBind(intent);
}
/**
* Called by the system when the service is first created.
*/
@Override
public void onCreate() {
Log.d(TAG, "onCreate: ");
super.onCreate();
}
/**
* Called by the system to notify a Service that
* it is no longer used and is being removed.
*/
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy: ");
super.onDestroy();
}
/**
* You should not override this method for your IntentService.
*/
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand: ");
return super.onStartCommand(intent, flags, startId);
}
/**
* Sets intent redelivery preferences.
*/
@Override
public void setIntentRedelivery(boolean enabled) {
Log.d(TAG, "setIntentRedelivery: ");
super.setIntentRedelivery(enabled);
}
}
- 在
AndroidMenifest.xml
中注册Service
<!-- 注册Intent Service -->
<service android:name="com.brain.interview.intent_service.MyIntentService">
<intent-filter>
<action android:name="com.brain.intentservice"/>
</intent-filter>
</service>
- 编写测试代码
/**
* 启动
*/
public void startIntentService1() {
// 操作一
Intent intent = new Intent();
intent.setAction("com.brain.intentservice");
intent.setPackage(getPackageName());
Bundle bundle = new Bundle();
bundle.putString("param", "打球");
intent.putExtras(bundle);
startService(intent);
// 操作二
Intent intent2 = new Intent();
intent2.setAction("com.brain.intentservice");
intent2.setPackage(getPackageName());
Bundle bundle2 = new Bundle();
bundle2.putString("param", "吃饭");
intent2.putExtras(bundle2);
startService(intent2);
}
- 输出
onCreate:
onStartCommand:
onStartCommand:
onHandleIntent: 任务 : 打球
onHandleIntent: 任务 : 吃饭
onDestroy:
从输出可以看出, 在执行完所有的任务后, 销毁了Service.
2. 源码分析
IntentService 源码并不复杂其实, 就是封装了 Handler + ThreadHandler
2.1 HandlerThread
普通的Thread主要用于进行耗时操作.HandlerThread内部常见了消息队列,外界需要通过Handler的消息方式通知HandlerThread来执行一个任务.由于HandlerThread的run() 是一个无限循环(Looper.loop()),因此当明确不需要时需要主动调用,quit() 或者 quitSafely() 来终止线程的执行.
HandlerThread 的run方法的源码如下 :
@Override
public void run() {
mTid = Process.myTid();
// 创建和当前线程绑定的Looper对象
Looper.prepare();
// 保存当前线程的Looper的一个引用
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
// 使用者,可以重写这个方法进行消息循环开启前的设置.
onLooperPrepared();
// 开启消息循环
Looper.loop();
mTid = -1;
}
HandlerThread的好处就是他带有Looper, 不用我们手动开启Looper, 有了Looper我们就可以绑定Handler了
2.2 IntentService
- 首先在来看
onCreate()
方法
@Override
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
// 创建一个 HandlerThread 并启动, HandlerThread 内部维护这一个Looper.
// 可以利用这个Looper来使用Handler机制..
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
// 保存Looper的引用, 便于在Service退出时.退出Looper
mServiceLooper = thread.getLooper();
// 创建Handler
mServiceHandler = new ServiceHandler(mServiceLooper);
}
- 首先创建了一个HandlerThread对象, 并且启动了该对象.
- 然后保存了HandlerThread中的Looper对象的一个引用, 便于在IntentService销毁时对出Looper. 否则该子线程将会一直运行.
- 创建了一个Handler和创年的HandlerThread绑定在一起.
通过上面的三步就实现了. 一个可以接收msg的Handler, 并且在绑定的子线程中执行消息处理.之后我们只需要通过Handler发送消息, 通过Intent传送数据就可以实现在子线程中处理数据了.
- 再看,Service每次启动都会调用的
onStartCommand()和onStart()
方法,主要看onStart
@Override
public void onStart(@Nullable Intent intent, int startId) {
// 发送消息.切换线程执行, 将Service的startId 发送过去, 便于stop Service
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
我们可以看出在onStart()
中的实现也是十分简单, 就是通过之前创建的Handler发送了一个消息.将intent数据发送过去, 同时还携带了一个参数startId . 之所以要携带这个id是因为在Handler中需要调用stopSelf()方法来停止Service, (下面的话有点通俗) 只有当所有的startdid都stop了, Service才会真正的退出.
- 再来看, Handler的实现
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
// 这个方法需要使用者实现.字节的逻辑, 在子线程中执行
onHandleIntent((Intent)msg.obj);
// 这个方法不会立即将Service结束掉, 会等到所有的onStart
// 注意1 : msg.arg1中保存的Service的startId
stopSelf(msg.arg1);
}
}
- 首先会调用
onHandleIntent(intent)
方法,并将数据传送进去.onHandleIntent(intent)
方发是一个虚方法需要子类实现, 使用者的业务逻辑也是写在这个方法中的, 前面说过改Handler是和创建的HandlerThread对象的Looper绑定在一起的因此,次方法在子线程中执行. - 当
onHandleIntent(intent)
方法执行完后, 就会调用stopSelf(msg.arg1)
, 通过前面的分析可知msg.arg1 中存放给的是startId. 当所有的startId都被stop后Service也就结束了.
- 继续
onDestroy()
方法
@Override
public void onDestroy() {
// Service 烧毁时, 退出线程
mServiceLooper.quit();
super.onDestroy();
}
Service结束后, 对于Service中启动的子线程是没有影响的.在这HandlerThread中有Looper因此不会自动退出, 需要手动调用quit方法.
IntentService注释版本代码如下
/**
* @author : Brian
* @date : 2017/6/29
*/
public abstract class IntentService extends Service {
private static final String TAG = "IntentService";
/**
* HandlerThread中获取的Looper, 便于在Service销毁时,退出线程.
*/
private volatile Looper mServiceLooper;
/**
* 该Handler和HandlerThread的Looper线程绑定在一起,
* 也就是说会在那个线程中执行消息处理.
*/
private volatile ServiceHandler mServiceHandler;
/**
* 线程名称
*/
private String mName;
private boolean mRedelivery;
/**
* Handler
*/
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
// 这个方法需要使用者实现.字节的逻辑, 在子线程中执行
onHandleIntent((Intent)msg.obj);
// 这个方法不会立即将Service结束掉, 会等到所有的onStart
// 注意1 : msg.arg1中保存的Service的startId
stopSelf(msg.arg1);
}
}
/**
* 子类构造方法调用
*/
public IntentService(String name) {
super();
mName = name;
}
/**
*
*/
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
// 创建一个 HandlerThread 并启动, HandlerThread 内部维护这一个Looper.
// 可以利用这个Looper来使用Handler机制..
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
// 保存Looper的引用, 便于在Service退出时.退出Looper
mServiceLooper = thread.getLooper();
// 创建Handler
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
// 发送消息.切换线程执行, 将Service的startId 发送过去, 便于stop Service
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
/**
* 每次启动Service都会调用这个方法.
*/
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
// Service 烧毁时, 退出线程
mServiceLooper.quit();
}
/**
* Unless you provide binding for your service, you don't need to implement this
* method, because the default implementation returns null.
* @see android.app.Service#onBind
*/
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
}
/**
* 这个方法在子线程中被调用, 同一时刻只会有一个Intent请求被处理. 在逻辑上处理过程
* 在一个独立的子线程中执行.一次如果这个方法中的处理时间太长就会阻塞在同一个IntentService
* 发起的其他请求. 当所有的请求都处理结束后,IntentService会自动销毁. 因此不需要调用者
* 手动调用stopSelf()方法
*/
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}