上一篇我们解说了IntentService,它呢是Service的子类,而且是个抽象类,它内部定义了一个onHandleIntent()方法,可以用来处理不同的后台任务,说道这里,我就不多说了,因为这篇博文的主题并不是IntentService,如果你想了解它,那么你可以看看这篇IntentService源码解读文章,不过我本人还是建议,先了解一下HandlerThread的内部实现还是比较好的,对你理解IntentService是非常有好处的,说到这里,言归正传,我们开始进入我们这篇博文的主题,HandleThread源码解析,听起来HandleThread是挺高大上,其实,他就是一个线程而已,内部实现也是非常简单的。
上面说道,HandleThread本身就是一个线程,那么我们当然要来看一看他的内部run()方法的实现了,对不对啊?代码如下:
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}
我们看到,这是一个空实现的方法,而且还是一个protected的,Java中规定,这是一个受保护的方法,只限于同类、同包以及子类可以访问,我们还看到,这个方法上还一句注释,那么它的大意是:如果需要在执行Looper.loop()方法前要做一些相关的准备工作,那么子类就可以通过重写该方法来完成。
上面我还留了一个疑团给大家,那么接下来,我就要解读一下在run方法里还会去调用notifyAll()方法,我们知道,他是用来唤醒线程的,如果线程池里有很多线程的话,那么它就会将线程池中所有的线程唤醒。好了,不多说,在解答这个问题之前,我们先来看一个实验:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyThread myThread = new MyThread();
myThread.start();
handler = new Handler(myThread.looper){
@Override
public void handleMessage(Message msg) {
Log.e(TAG,"msg Test...");
}
};
handler.sendEmptyMessage(1);
}
//自定义个子线程
class MyThread extends Thread{
Handler handler;
Looper looper;
@Override
public void run() {
Looper.prepare();
looper.myLooper();
handler = new Handler(){
@Override
public void handleMessage(Message msg) {
Log.e(TAG,"线程名字 : "+Thread.currentThread().getName());
}
};
Looper.loop();
}
}
}
上面这段代码,我们模拟了线程切换,那么上面这段代码会有什么问题呢?其实隐患不大,真不大,它就会让你的程序崩溃而已,就这么大,呵呵,上面开了个玩笑,那么为什么会出现这个问题呢?其实这里涉及到线程并发的问题,当我们的线程之间在切换,可能我那个线程的Looper实例还没创建,这样就会导致空指针问题,问题如下图:
那么上面那个问题如何来解决呢?好了,该我们HandlerThread出场了,好了,下面呢,我们改成HandleThread类来做这个事情,看它会不会崩溃,改进代码如下:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//MyThread myThread = new MyThread();
//myThread.start();
HandlerThread myThread = new HandlerThread("哈哈");
myThread.start();
handler = new Handler(myThread.getLooper()){
@Override
public void handleMessage(Message msg) {
Log.e(TAG,"msg Test...");
}
};
handler.sendEmptyMessage(1);
}
我们发现,并没有崩溃,哈哈,perfect!那么到了这里,我们就不经要思考了,为什么HandlerThread能保证程序不崩溃呢?那么大家还记得我们之前我们在阅读HandleThread里面run()方法吗?它内部是不是调用了一个notifyAll()方法呢?看到这里,大家都大致明白了吧,有唤醒,当然就有wait方法啦,上面我们代码调用了HandlerThread中getLooper()方法,那么这个getLooper()方法里,到底干了些什么事情?好,我们就来看一看这个方法的实现,代码如下:
/**
* This method returns the Looper associated with this thread. If this thread not been started
* or for any reason is isAlive() returns false, this method will return null. If this thread
* has been started, this method will block until the looper has been initialized.
* @return The looper.
*/
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;
}
看看上面代码做了什么,如果当前这个线程没有存活,那么直接返回null,接下来,我看重点,while里面的的代码,发现它判断线程是否存活,以及当前成员变mLooper是否为null,如果为isAlive()为true并且mLooper为null的话,他就会让当前线程进入等待,这样就避免了上述我们平常开发时所碰到的空指针问题。当然,HandleThread类还有一个特殊应用场景,就是IntentService,如果要了解IntentService就看这篇 IntentService源码解读文章吧,在使用时,有一点我们需要注意,那就是HandleThread类中run()方法一旦执行,将会无限循环,因为它里面调用了loop()方法,loop方法就是个无限循环,来轮训消息,具体你可以看看 阅读源码,让你彻底理解Handler、Message、Looper之间的关系这篇文章,就可以知道loop()里到底是怎么实现的了,所以呢,当我们用完,不需要在使用的时候,我们就可以通过调用quit()方法和quitsafely()方法来终止线程的执行。好了,HandleThread到这里就分析完毕了,好累,欢迎大家拍砖、吐槽,谢谢!