Android多线程(三)HandlerThread源码原理解析

HandlerThread实例

  在上一遍中文章Android消息处理机制—Handler、Message、Looper源码原理解析中我们学习了Looper、Handler、Message之间的关系,在子线程中创建Handler的过程稍显复杂,有没有一种更简单的办法呢,答案是肯定的,其实Android已经为我们封装了一个Handler、Looper的结合体——HandlerThread,我们来看一个HandlerThread的实例:

public class MainActivity extends Activity {

    private HandlerThread mHandlerThread;
    //工作在子线程中的Handler
    private Handler mSecondHandler;
    //工作在UI线程中的Handler
    private Handler mUIHandler;
    private int MESSAGE_WORK = 0X01;
    private int MESSAGE_DONE = 0X02;
    private Button mButton;
    private TextView mTextView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mButton = (Button) findViewById(R.id.send);
        mTextView = (TextView) findViewById(R.id.tx);


        mUIHandler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
            //UI线程中的Handler收到后信息更新界面
                super.handleMessage(msg);
                if (msg.what == MESSAGE_DONE) {
                    mTextView.setText("the number is : " + msg.arg1);
                }
            }
        };

        mHandlerThread = new HandlerThread("test");
        //必须调用
        mHandlerThread.start();

        mSecondHandler = new Handler(mHandlerThread.getLooper()){
            @Override
            public void handleMessage(Message msg) {
                //工作在子线程中
                super.handleMessage(msg);
                try {
                //模拟耗时操作
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    //耗时操作完成后通过UIHandler通知UI线程更新界面
                    Message done = new Message();
                    done.what = MESSAGE_DONE;
                    Random rand = new Random();
                    done.arg1 = rand.nextInt(100);
                    mUIHandler.sendMessage(done);
                }
            }
        };
        //发送消息给子线程中的Handler
        mSecondHandler.sendEmptyMessage(0x123);
        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mSecondHandler.sendEmptyMessage(MESSAGE_WORK);
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //不再使用时释放Looper
        mHandlerThread.quit();
    }
}

  在上面的例子中,我们在子线程中使用创建Handler来处理消息时只需创建一个HandlerThread,并在创建子线程Handler的时候传入HandlerThread.getLooper() ,不再需要调用Looper.prepare()和Looper.loop(),甚至不用创建Thread,看上去是不是简单多了,接下来看看Handlerthread是怎样工作的。

源码分析

其实HandlerThread的源码只有200行不到:

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }

    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }

    protected void onLooperPrepared() {
    }

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

    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;
    }
}

  从以上源码中可以知道,其实HandlerThread其实是一个Thread,我们通过它的构造函数指定HandlerThread的名字,设置线程的优先级,默认情况的线程级别是0。既然是继承Thread类,那最重要的肯定是重写run()方法了,在HandlerThread的run()中首先通过Looper.prepare()来获取创建Looper实例,所以我们要在创建Handler之前要调用start()方法,然后回调run()去创建Looper对象,在run()方法中通过线程同步去给当前成员变量mLooper赋值,当mLooper = Looper.myLooper()完成之后,通过notifyAll()通知mLooper已经创建完成,然后getLooper()时才能获取到Looper对象,否则getLooper()这个方法就会一直wait(),直到Looper被初始化。此外,我们可以通过重写onLooperPrepared()这个方法在Looper.looper()开始前执行我们需要的一些操作,然后run()中调用Looper.loop(),这样Looper就开始工作了。
  通过以上的分析可知,原来HandlerThread已经为我们创建好了Looper对象,我们只需要在创建Handler时通过getLooper()方法将Looper实例传入即可,这样一套完整的消息处理机制就完成了,当我们不在需要HandlerThread时记得通过下面两个方法Looper循环:

public boolean quit() {
    Looper looper = getLooper();
    if (looper != null) {
        looper.quit();
        return true;
    }
    return false;
}

public boolean quitSafely() {
    Looper looper = getLooper();
    if (looper != null) {
        looper.quitSafely();
        return true;
    }
    return false;
}

这两个方法的不同点在于,quitSafely()会在清空消息之前继续派发所有非延迟消息,而quit()则会立即清空所有的非延迟消息和延迟消息(通过sendMessageDelayed或通过postDelayed等方法发送的为延迟消息)。

你可能感兴趣的:(Android)