Android进阶二十 HandlerThread总结

概述

在日常开发中,我们经常会通过new Thread(){}.start();的方式来开辟一个新的线程。但是如果我们想要多次执行任务的时候,通过这种方式我就会创建多个线程,这样会使我们的程序运行起来越来越慢。通常情况下我会采用HandlerThread的方式来开辟一个线程,那么HandlerThread是什么呢?今天我们来介绍一下HandlerThread。

正文

HandlerThread是Thread的一个子类,HandlerThread自带Looper使他可以通过消息队列来重复使用当前线程,节省系统资源开销。这是它的优点也是缺点,每一个任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理。它的使用也比较简单

HandlerThread thread = new HandlerThread("MyHandlerThread");
thread.start();
//Looper在子线程中的handler
mHandler = new Handler(thread.getLooper());
//mHandler.post(new Runnable(){...});

接下来我们写一个完整的Demo,然后在分析一下它的实现原理。

public class MainActivity extends AppCompatActivity {
    HandlerThread mCheckMsgThread;
    boolean isUpdateInfo = true;
    private int mCount = 0;
    private static final int MSG_UPDATE_INFO = 0x110;

    //与UI线程管理的handler
    private Handler mHandler = new Handler();
    private Handler mCheckMsgHandler;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initBackThread();
    }

    private void initBackThread()
    {
        mCheckMsgThread = new HandlerThread("check-message-coming");
        mCheckMsgThread.start();
        mCheckMsgHandler = new Handler( mCheckMsgThread.getLooper())
        {
            @Override
            public void handleMessage(Message msg) {
                //Thread.sleep(1000) 模拟耗时操作
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        ((TextView)findViewById(R.id.id_txt)).setText((mCount++)+"");
                    }
                });
                if(isUpdateInfo)
                    mCheckMsgHandler.sendEmptyMessage(MSG_UPDATE_INFO);

            }
        };


    }

    @Override
    protected void onPause() {
        super.onPause();
        isUpdateInfo = false;
        mCheckMsgHandler.removeMessages(MSG_UPDATE_INFO);
    }

    @Override
    protected void onResume() {
        super.onResume();
        isUpdateInfo = true;
        mCheckMsgHandler.sendEmptyMessage(MSG_UPDATE_INFO);

    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mCheckMsgThread.quit();
    }
}

这样就可以看到在屏幕上每个一秒的计数!

源码分析

上面demo中,新建一个HandlerThread并启动:

mCheckMsgThread = new HandlerThread("check-message-coming");
 mCheckMsgThread.start(); 

对应源码:

package android.os;


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

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

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

看到了什么,其实我们就是初始化和启动了一个线程;然后我们看run()方法,可以看到该方法中调用了Looper.prepare(),Loop.loop();

prepare()中创建了一个Looper对象,并且把该对象放到了该线程范围内的变量中(sThreadLocal),在Looper对象的构造过程中,初始化了一个MessageQueue,作为该Looper对象成员变量。

loop()就开启了,不断的循环从MessageQueue中取消息处理了,当没有消息的时候会阻塞,有消息的到来的时候会唤醒。

接下来,我们创建了一个mCheckMsgHandler,是这么创建的:

mCheckMsgHandler = new Handler(mCheckMsgThread.getLooper())

对应源码:

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

mCheckMsgThread.getLooper()返回的就是我们在run方法中创建的mLooper。

那么Handler的构造呢,其实就是在Handler中持有一个指向该Looper.mQueue对象,当handler调用sendMessage方法时,其实就是往该mQueue中去插入一个message,然后Looper.loop()就会取出执行。

好了,到这我们就分析完了,其实就几行代码;不过有一点我想提一下:

如果你够细心你会发现,run方法里面当mLooper创建完成后有个notifyAll(),getLooper()中有个wait(),这是为什么呢?因为的mLooper在一个线程中执行,而我们的handler是在UI线程初始化的,也就是说,我们必须等到mLooper创建完成,才能正确的返回getLooper();wait(),notify()就是为了解决这两个线程的同步问题。

整体流程

当我们使用HandlerThread创建一个线程,它statr()之后会在它的线程创建一个Looper对象且初始化了一个MessageQueue(消息队列),通过Looper对象在他的线程构建一个Handler对象,然后我们通过Handler发送消息的形式将任务发送到MessageQueue中,因为Looper是顺序处理消息的,所以当有多个任务存在时就会顺序的排队执行。当我们不使用的时候我们应该调用它的quit()或者quitSafely()来终止它的循环。

猜你喜欢

转载自blog.csdn.net/lixpjita39/article/details/79341315
今日推荐