Android HandleThread源码分析

           上一篇我们解说了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;
    }

从上面这段代码可以知道,拿到当前线程标识Id,然后调用Looper类中prepare()方法给当前线程创建Looper实例,接着调用Looper中的myLooper()方法,获取当前Looper实例,并且用一个成员变量保存,紧接着,调用notifyAll()方法,唤醒所有正在等待的线程,那么这里为什么会调用一个notifyAll()呢?这里暂时不说,留个疑团放在这里,到后面在解答,好,下面又设置了线程的优先级,然后呢,调用了onLooperPrepared()方法,那么这个方法是干什么的呢?不着急,我们先把这个方法看完,我们看到,随后又调用了Looper.loop()方法,开始监视MesaageQueue。如果你对Handler了解的还不熟悉的话,你可以看看这篇 阅读源码,让你彻底理解Handler、Message、Looper之间的关系文章。好,我们下面就开始来分析一下onLooperPrepared()方法:

/**
     * 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实例还没创建,这样就会导致空指针问题,问题如下图:

Android HandleThread源码分析_第1张图片

      那么上面那个问题如何来解决呢?好了,该我们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);

    }


Android HandleThread源码分析_第2张图片


     我们发现,并没有崩溃,哈哈,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到这里就分析完毕了,好累,欢迎大家拍砖、吐槽,谢谢!


你可能感兴趣的:(移动开发)