美文网首页
Android HandlerThread全面解析

Android HandlerThread全面解析

作者: CyanStone | 来源:发表于2018-11-20 16:55 被阅读0次

    在对Android异步消息处理机制源码剖析Android AsyncTask源码剖析后,下面对Android中的另一个和异步消息机制相关的类-HandlerThread进行全面解析。

    为什么要有HandlerThread?

     我们已经知道,主线程与子线程之间的通信,可以依靠Handler,Looper和MessageQueue来实现。一个线程中可以有唯一的Looper对象,负责消息循环;一个Looper中都有唯一的MessageQueue,管理者消息队列;Handler在发消息前,必须与一个Looper进行绑定,也就与MessageQueue进行了绑定。一切准备就绪后,可以通过Handler把消息Message发送出去,Message会在MessageQueue中入队,然后等待Looper把消息取出并交给发送消息体的Handler进行消息的处理。
     如果是主线程向子线程进行通信,在创建Handler之前,则必须在子线程中调用Looper.prepare()方法为线程初始化一个Looper对象。一旦忘记调用Looper.prepare()方法,在创建Handler的时候会抛出异常。

    public Handler(Callback callback, boolean async) {
        ...
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");
        }
       ...
    }
    

     所以Google为了避免开发者忘记调用Looper.prepare()而导致的异常,对Thread类进行了封装,使得Thread类在初始化的时候便有了一个Looper,这便是我理解的HandlerThread产生的由来。如有不对的地方,欢迎指正交流。


    HandlerThread的源码剖析

     HandlerThread源码非常的少,只是对Thread进行了简单的封装,如果对Android异步消息机制了解的同学,理解它的源码非常的简单。下面来看HandlerThread的源码。

    public class HandlerThread extends Thread {
        int mPriority;  //线程执行优先级
        int mTid = -1;  //调用线程的标识符
        Looper mLooper;  //线程内部的Looper对象,一个线程只有一个Looper对象
        private @Nullable
        Handler mHandler; //与Looper绑定的Handler对象
    
        public HandlerThread(String name) {
            super(name);
            //设置优先级
            mPriority = Process.THREAD_PRIORITY_DEFAULT;
        }
    
        public HandlerThread(String name, int priority) {
            super(name);
            mPriority = priority;
        }
       //Looper开启循环前调用,子类可按需覆写
        protected void onLooperPrepared() {
        }
    
        @Override
        public void run() {
            //返回调用线程的标识符
            mTid = Process.myTid();
            //初始化线程本地变量Looper
            Looper.prepare();
            synchronized (this) {
                //从Looper中拿到本线程的Looper对象
                mLooper = Looper.myLooper();
                notifyAll(); //唤醒线程
            }
            Process.setThreadPriority(mPriority);
            onLooperPrepared();  //回调方法,在loop之前,子类可按需覆写实现
            Looper.loop();
            mTid = -1;
        }
        //返回looper对象
        public Looper getLooper() {
            //如果线程不是可用状态,则返回null
            if (!isAlive()) {
                return null;
            }
            // If the thread has been started, wait until the looper has been created.
            //如果线程被start了,但是mLooper还没有初始化,则让线程进入等待状态,直到mLooper对象被初始化后线程被唤醒
            synchronized (this) {
                while (isAlive() && (mLooper == null)) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                    }
                }
            }
            return mLooper;
        }
    
        @NonNull
        //懒加载初始化Handler的单例对象,该handler与此线程获取的Looper进行绑定
        public Handler getThreadHandler() {
            if (mHandler == null) {
                mHandler = new Handler(getLooper());
            }
            return mHandler;
        }
        //退出,执行的是looper.quit,其实执行的是Looper中MessageQueue.quit方法
        public boolean quit() {
            Looper looper = getLooper();
            if (looper != null) {
                looper.quit();
                return true;
            }
            return false;
        }
        //同上述方法,执行的是MessageQueue.quit方法
        public boolean quitSafely() {
            Looper looper = getLooper();
            if (looper != null) {
                looper.quitSafely();
                return true;
            }
            return false;
        }
        //返回调用线程的标识
        public int getThreadId() {
            return mTid;
        }
    }
    

    以上便是HandlerThread的全部源码,非常的简短,下面做以下几点说明:

    • HandlerThread继承自Thread,所以它的本质还是线程的一种实现;
    • HandlerThread内部已经有了一个Looper对象,在线程启动的时候,会初始化线程本地变量Looper;
    • HandlerThread内部有Handler对象,但采用的是懒加载的单例,在使用之前并未进行初始化;Handler对象绑定的Looper就是本线程的Looper对象;
    • 在调用getThreadHandler()方法和getLooper()方法之前,必去确保线程已经启动了(调用了start()方法),否则线程会进入等待状态,直到在run()方法内部mLooper对象被赋值;
    • 在Looper开启循环(调用loop()方法)之前,会执行onLooperPrepared()方法,它默认是一个空实现,可在子类中按需覆写实现,注意,它的执行逻辑是在子线程,所以不要进行UI操作;
    • quit方法和quitSafely方法调用的是Looper对象的相应方法,其实最终调用的都是Looper内部MessageQueue的quit方法,这个在Android异步消息处理机制源码剖析分析的已经很清楚了,不明白的同学可以去了解下;
    • HandlerThread只是把线程和Looper进行了简单的封装,剩下的很多操作跟异步消息处理机制是一样的;

    HandlerThread使用场景

    Android异步消息处理机制源码剖析文章中,主线程向子线程进行通信,给了一个case:

         //创建子线程
    class WorkThread extends Thread {
        private Looper looper; //取出该子线程的Looper
        public void run() {
            Looper.prepare(); //创建该子线程的Looper
            looper = Looper.myLooper(); //取出该子线程的Looper
            Looper.loop(); //只要调用了该方法才能不断循环取出消息
        }
    }
    
    private Handler mHandler;
    
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        thread = new WorkThread();
        thread.start();
        //创建Handler时把looper做入参,把Handler与Looper绑定在一起
        mHandler = new Handler(thread.looper) {
            public void handleMessage(android.os.Message msg) {
                //在子线程中处理消息的逻辑
            };
        };
        mHandler.senMessage(Message.obtain());
    }
    

    上述例子很简单,它其实跟HandlerThread的实现思路是一致的,所以可以改成以下方式:

    private private Handler mHandler;
    class WorkThread extends HandlerThread {
        @Override
        public void run() {
          super.run();
          //执行业务操作
        }
    
        @Override
        protected void onLooperPrepared() {
           //按需选择是否覆写,在loop之前想做的操作
        }
    }
    
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        HandlerThread thread = new WorkThread();
        thread.start();
        //通过ThreadHander去获取Looper来创建Handler
        mHandler = new Handler(thread.getLooper()) {
            public void handleMessage(android.os.Message msg) {
                //在子线程中处理消息的逻辑
            };
        };
        mHandler.senMessage(Message.obtain());
    

    另外,如果不需要Handler对消息进行处理,也可以调用以下方式直接获取HandlerThread中的Handler发送消息:

        HandlerThread thread = new WorkThread();
        thread.start();
        //通过ThreadHander去获取Looper来创建Handler
        mHandler = thread.getThreadHandler();
        mHandler.senMessage(Message.obtain());
    

     在Android异步消息处理机制源码剖析中分析知道,在Looper中获取消息后,调用Handler.diapatchMessage()方法进行处理,处理的优先级顺序依次是:Message的callback(Runnable对象) -> Handler的Callback(实现了handleMessage方法的Callback接口实现类对象) -> Handler自身的handleMessage()方法。所以如果用HanderThread中的Handler想要处理Message的话,可以用以下两种方式:

    • 一种是给Handler设置Callback对象,需要实现Callback接口,handlerMessage()方法的返回值表示是否要消耗掉这个Message,不再调用Handler自己的handleMessage()方法,由于HandlerThread内部的Handler并没有覆写这个空方法,所以这里返回值true和false都可以:
        HandlerThread thread = new WorkThread();
        thread.start();
        //通过ThreadHander去获取Looper来创建Handler
        mHandler = thread.getThreadHandler();
        mHandler.setCallback(new Handler.Callback() {
            @Override
            public boolean handleMessage(Message msg){
                //处理消息的逻辑
            }
        });
        mHandler.senMessage(Message.obtain());
    
    • 另一种方式,便是在获取一个Message对象的时候,给它设置callback:
        HandlerThread thread = new WorkThread();
        thread.start();
        //通过ThreadHander去获取Looper来创建Handler
        mHandler = thread.getThreadHandler();
        final Message msg = Message.obtain(mHandler, new Runnable(){
              @Override
              public void run() {
                    //执行消息的处理,可以通过msg去获取传递的值进行逻辑处理
              }
        });
        mHandler.senMessage();
    

    参考链接

    相关文章

      网友评论

          本文标题:Android HandlerThread全面解析

          本文链接:https://www.haomeiwen.com/subject/cwxxqqtx.html