版权声明:本文为博主原创文章,欢迎大家转载!
转载请标明出处: blog.csdn.net/guiying712/…,本文出自:【张华洋的博客】
在这篇文章中我将介绍 在 Android 中的 IntentService,在分析 IntentService的原理时,将顺便分析 IntentService中使用到的 HandlerThread 。
IntentService
IntentService 继承于Android四大组件中的 Service, 而 IntentService 与 Service 的区别在于它可以处理异步请求,我们都知道 Service 中的代码都是默认运行在主线程当中的,如果直接在 Service 中去处理耗时的任务,就很容易出现 ANR的 情况,而 IntentService 则是直接在子线程中工作的。另外当我们使用 startService(Intent) 方法 启动 IntentService 后,IntentService 就会在 工作线程中处理每一个 Intent ,并且在完成这些任务后停止它自己。
还是老规矩,分析源码之前,先看下怎么使用 IntentService:
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService"); // 必须调用父类的有参构造函数
}
@Override
protected void onHandleIntent(Intent intent) {
// 打印当前线程的名称,证明是在子线程中
Log.d("MyIntentService", "Thread id is " + Thread.currentThread().getName());
}
@Override
public void onDestroy() {
super.onDestroy();
// 为了证明IntentService在处理完工作后停止了自己
Log.d("MyIntentService", "onDestroy");
}
}
可以看,使用 IntentService 真的是非常简单,我们只需要继承 IntentService ,并提供一个构造函数,并且必须在其内部调用父类的有参构造函数,然后重写 onHandleIntent(Intent intent)方法,在 onHandleIntent 方法中可以去处理一些具体的业务逻辑,而且不用担心ANR的问题,因为这个方法已经是在子线程中运行了。
接下来我们看下 IntentService 的源码:
public class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public IntentService(String name) {
super();
mName = name;
}
@Override
public void onCreate() {
super.onCreate();
//创建一个HandlerThread的对象
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();//创建HandlerThread对象后就调用start()方法开启线程
//获取HandlerThread中创建的 Looper
mServiceLooper = thread.getLooper();
//使用这个 Looper创建一个 Handler
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
}
从源码中,我们可以看到之所以在 MyIntentService的构造函数中必须在调用父类的有参构造函数,是因为IntentService需要为它的工作线程起一个名字,用于我们debug的时候区分。这个我们可以在 onCreate()方法中的这段代码得到印证:
HandlerThread thread = new HandlerThread(“IntentService[” + mName + “]”); // mName 就是我们在构造函数中传入的参数
当我们通过 startService(Context, Intent) 方法启动 IntentService 后,就会回调 IntentService 的 onCreate 和 onStart 方法:
1、首先在回调onCreate()方法中 创建一个 HandlerThread,并开启这个线程,然后获取HandlerThread中创建的 Looper ,使用这个 Looper创建一个 ServiceHandler 。
2、接着就会回调 onStart(@Nullable Intent intent, int startId) 方法,我们可以看到在 onStart 方法中,会通过 ServiceHandler 拿到一个Message,并使Message携带我们的请求参数,然后通过 ServiceHandler 将这个Message发送出去。如果有不懂 Handler 工作原理的可以查看这篇文章:Android Handler源码解析 。
3、ServiceHandler 发送的 Message 最终会被分发到 IntentService 的内部类 ServiceHandler 的 handleMessage(Message msg) 方法中。在这里就会调用 IntentService 的抽象方法 onHandleIntent(@Nullable Intent intent),并且这个方法上有个注解:@WorkerThread,代表这个方法是在工作线程中被调用。然后就会调用 Service 的 stopSelf 方法 停止这个服务,因此你无需调用 stopSelf 方法。
4、一旦 IntentService 调用了 stopSelf 方法后,就会回调 onDestroy() 方法, 我们在 HandlerThread 中创建的 Looper 就会退出循环。
另外在使用 IntentService 时需要注意以下事项 :
1、在使用 IntentService 时,不要重写 onStartCommand 方法,而是应该重写 onHandleIntent 方法,当 IntentService 被 start 后,系统回调的是 onHandleIntent 。
2、不要在 你的 IntentService 中提供 Service 的 onBind 方法,你不需要实现这个方法,因为 IntentService 默认实现了这个方法并返回 null 。
HandlerThread
说起 IntentService 就不得不讲讲 HandlerThread,HandlerThread 可以说是Android中应用非常广泛的一个类,它继承自 Thread,用于开启一个自带 Looper 的 新线程,这个新线程中创建的 Looper 可以用来创建 Handler类,因此 HandlerThread 经常与 Handler 搭配使用,这也是类名为什么称为HandlerThread 的原因。
注意 :Thread类 的 start() 方法仍然需要调用。
我们在 IntentService 中已经看到 HandlerThread是如何 Handler搭配使用的,因此这里我们就直接查看HandlerThread的源码 :
public class HandlerThread extends Thread {
Looper mLooper;
private @Nullable Handler mHandler;
protected void onLooperPrepared() {
}
@Override
public void run() {
...
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
...
onLooperPrepared();
Looper.loop();
...
}
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
}
在分析HandlerThread 的源码之前,我们先复习下Java的线程。
在 Java 中每个线程都是通过某个特定Thread对象所对应的方法 run() 来完成其操作的,方法 run() 称为线程体,它包含了要执行的这个线程的内容。我们通过调用Thread类的 start() 方法来就可以启动一个线程,一旦调用 start() 后,线程就会被放到等待队列,等待CPU调度,但并不一定要马上开始执行,只是将这个线程置于可动行状态。
在Java当中,线程通常有五种状态:创建、就绪、运行、阻塞和死亡:
第一是创建状态。生成线程对象,并没有调用该对象的start方法,这时线程处于创建状态。
第二是就绪状态。当调用了线程对象的 start 方法之后,该线程就进入了就绪状态,但是此时线程调度程序还没有把该线程设置为当前线程,此时处于就绪状态。在线程运行之后,从等待或者睡眠中回来之后,也会处于就绪状态。
第三是运行状态。线程调度程序将处于就绪状态的线程设置为当前线程,此时线程就进入了运行状态,开始运行 run 函数当中的代码。
第四是阻塞状态。线程正在运行的时候被暂停,通常是为了等待某个事件的发生(比如说某项资源就绪)之后再继续运行。sleep,suspend,wait等方法都可以导致线程阻塞。
第五是死亡状态。如果一个线程的 run 方法执行结束或者调用stop方法后,该线程就会死亡。对于已经死亡的线程,无法再使用 start 方法令其进入就绪。
在 HandlerThread 的 run() 方法中,先调用 Looper.prepare() 在当前线程创建一个 Looper ,然后通过 Looper.myLooper() 获取到这个 Looper ,接下来执行了 onLooperPrepared() 方法,如果我们需要在 Looper进入无限循环之前执行一些设置,我们就可以重写这个方法。之后便调用Looper.loop() 使 Looper开始运行。
接着我们在看下 HandlerThread 的 getLooper() 方法,这个方法会返回与当前线程关联的 Looper(就是在 run() 中创建 的 Looper),如果这个线程还没有启动(这也是为什么我们创建 HandlerThread 后就要调用 start() 方法的原因),或者一些原因导致 Thread的 isAlive()返回 false,就会导致 getLooper() 返回 null。如果这个线程已经启动了, getLooper() 就会一直阻塞,直到 Looper 初始化完成。
我们注意到,在 HandlerThread 中也提供了 quit() 方法 用于退出 HandlerThread 的 Looper ,由于 IntentService 在销毁时会主动调用 looper.quit() 方法使 Looper 退出,所以如果你在使用完 HandlerThread 后也需要主动调用 quit() 方法。