HandlerThread使用和源码解析

HandlerThread是什么

HandlerThread其本质就是一个Thread,只不过其内部帮我们封装了Looper,在线程内部,代码是串行处理。

如果你愿意,完全可自己写

HandlerThread的主要作用就是在新线程中执行一些耗时的操作,因其使用了Looper,MessageQueue,所以只能顺序的执行任务,高并发的执行任务还需使用线程池。

然并卵,个人感觉HanlderThread完全可以用线程池来代替

HanlderThread使用

public class MainActivity extends AppCompatActivity {

    private Button mBtn1, mBtn2, mBtn3, mBtn4;
    private HandlerThread mHandlerThread;
    private Handler ziHandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initClick();
    }

    private void initView() {
        mBtn1 = (Button) findViewById(btn1);
        mBtn2 = (Button) findViewById(R.id.btn2);
        mBtn3 = (Button) findViewById(R.id.btn3);
        mBtn4 = (Button) findViewById(R.id.btn4);
    }

    private void initClick() {
        mBtn1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                btn1Click();
            }
        });
        mBtn2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                btn2Click();
            }
        });
    }

    private static Handler  zhuHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            Log.d("MainActivity:", "zhuHandler-"+Thread.currentThread());

            Log.d("MainActivity:", "zhuHandler-"+msg.arg1);
        }
    };

    private void btn1Click() {
        mHandlerThread = new HandlerThread("Handler_Thread"){
            @Override
            protected void onLooperPrepared() {
                //在Looper.loop()消息循环之前调用
                Log.d("MainActivity:", "onLooperPrepared-"+Thread.currentThread());
            }
        };

        mHandlerThread.start();
        ziHandler = new Handler(mHandlerThread.getLooper()){
            @Override
            public void handleMessage(Message msg) {

                Log.d("MainActivity:", "ziHandler-"+Thread.currentThread());
                Log.d("MainActivity:", "ziHandler-"+msg.arg1);
                if (msg.arg1 == 2) {//满足某一个条件后给主线程发消息
                    Message message = zhuHandler.obtainMessage();
                    message.arg1 = 1;
                    zhuHandler.sendMessage(message);
                }
                mHandlerThread.quit();
            }
        };
    }

    private void btn2Click() {
        Message message = ziHandler.obtainMessage();
        message.arg1 = 2;
        ziHandler.sendMessage(message);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //退出
        mHandlerThread.quit();
    }
}

HandlerThread 源码分析

mHandlerThread = new HandlerThread(“Handler_Thread”);
mHandlerThread.start();

因其继承Thread,所以这就是在开启一个指定名字的线程。源码:

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

Priority代表线程的优先级,默认为0,也可指定优先级
然后看下run()方法:

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

第3行创建了一个Looper对象,Looper内部又创建MessageQueue,并把Looper对象保存到ThreadLocal中
第4-7行同步拿到Looper对象,并通过notifyAll方法唤醒等待线程
第8行设置线程的优先级
第9行是在执行loop()方法之前做一些初始化工作
第10行开始消息循环
第11行只有到消息循环结束才会调用

对于Hanlder、Looper、MessageQueue的工作机制不熟悉的可以看这篇文章

注意:进入到消息循环后,loop()下边的代码是不会执行的,只有退出了消息循环才会去执行

接下来创建Hanlder对象

ziHandler = new Handler(mHandlerThread.getLooper()){
            @Override
            public void handleMessage(Message msg) {

                Log.d("MainActivity:", "ziHandler-"+Thread.currentThread());
                Log.d("MainActivity:", "ziHandler-"+msg.arg1);
                if (msg.arg1 == 2) {//满足某一个条件后给主线程发消息
                    Message message = zhuHandler.obtainMessage();
                    message.arg1 = 1;
                    zhuHandler.sendMessage(message);
                }
                mHandlerThread.quit();
            }
        }

说明:每个线程只能有一个Looper对象,多次调用Looper.prepare()方法会报错,MessageQueue对象是在Looper内部创建的,所以Looper对象唯一就能保证MessageQueue对象唯一。
Handler对象创建后必须与某一Looper对象进行绑定,否则就会报错,多个Handler对象可以绑定同一个Looper对象。

实在不懂可先熟悉下Handler源码解析这篇文章

再看getLooper()源码:

public Looper getLooper() {
        //判断线程是否活着
        if (!isAlive()) {
            return null;
        }
        // 如果线程运行着,则需要等待Looper对象创建后再做返回,否则等待
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    //等待,释放锁
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

前面说过,Handler创建后必须绑定某一个Looper,这里在创建Handler对象时也是通过while (isAlive() && mLooper == null)先判断了下Looper是否为空,如果为空则wait()等待,这样也就避免Handler无法绑定Looper而报错。
当HandlerThread开始运行后,在run()方法中会调用notifyAll()方法通知所有线程进入就绪状态。

注意:在主线程创建的Hanlder不需要人为创建Looper,因为在应用启动时,地层已经帮我们创建好了。

退出循环

当需要退出消息循环时,可以调用HandlerThread提供两个方法quit()和quitSafely(),这两个方法又调用了Looper的quit()和quitSafely()。源码:

public void quit() {
        mQueue.quit(false);
    }

public void quitSafely() {
        mQueue.quit(true);
    }

可以看到最终调用了MessageQueue的quit()方法

void quit(boolean safe) {
        ....省略....
        if (safe) {
            removeAllFutureMessagesLocked();
        } else {
            removeAllMessagesLocked();
        }
        ....省略....
    }

先看一下removeAllMessagesLocked源码:

private void removeAllMessagesLocked() {
        Message p = mMessages;
        while (p != null) {
            Message n = p.next;
            //回收消息
            p.recycleUnchecked();
            p = n;
        }
        mMessages = null;
    }

很简单就是把消息池中的消息全部清空并回收,无论是延迟消息还是非延迟消息。

再来看一下removeAllFutureMessagesLocked源码:

private void removeAllFutureMessagesLocked() {
        final long now = SystemClock.uptimeMillis();
        Message p = mMessages;
        if (p != null) {
            if (p.when > now) {
                removeAllMessagesLocked();
            } else {
                Message n;
                for (;;) {
                    n = p.next;
                    if (n == null) {
                        return;
                    }
                    if (n.when > now) {
                        break;
                    }
                    p = n;
                }
                p.next = null;
                do {
                    p = n;
                    n = p.next;
                    p.recycleUnchecked();
                } while (n != null);
            }
        }
    }

通过if(p.when > now)可知道,此方法只会清空消息队列中所有的延迟消息而所有非延迟消息还是会发送给绑定的Handler去处理.

quitSafely和quit区别

quitSafely在退出消息循环之前会派发完所有非延迟任务
quit则会全部清空未执行完的任务

当然不管调用那个方法退出,消息循环都将不再接受新的任务加入消息队列

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值