【安卓开发艺术探索】第10章 消息机制Handler 笔记

这一章主要讲Handler、Looper、MessageQueue这几者之间工作的机制,其实对于上层开发者,Handler用起来容易,但其背后的机制、尤其是Looper的机制却比较复杂,对某些部分,我暂时只能从一定程度上理解。

ThreadLocal

对于每一个线程,需要独立拥有一个Looper来进行消息管理。这个时候就需要派上ThreadLocal了。
ThreadLocal适合去维护一些以线程为作用域、不同线程使用的是不同的拷贝这种情景。
参考如下链接:http://blog.csdn.net/lufeng20/article/details/24314381 讲得比较清楚。
其实现是依赖Thread类中有如下定义:ThreadLocal.ThreadLocalMap threadLocals = null;也就是每一个Thread对象都有一个threadLocals变量,类型是ThreadLocalMap,而这个类中有如下定义:private Entry[] table;,这个Entry就是用来存放每一个ThreadLocal对象的容器。

        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

所以容易理解了,ThreadLocal存储过程就是以ThreadLocal自身的对象为key,泛型Object作为value,保存到ThreadLocalMap里的table数组中。而每个Thread都会拥有各自的ThreadLocalMap。

Looper+MessageQueue原理

调用Looper.prepare,来在一个新的线程中做初始化准备,这里面包括了构造一个新的Looper,保存当前的线程,构造新的MessageQueue。
调用Looper.loop,开始进入循环来等待接收消息。其主要是通过调用messageQueue的next()来等待新消息,再取出message,调用message.target.dispatchMessage(message)来处理此消息。message的target是Handler。这样即可完成消息的传递了。

似乎一切顺理成章,但有没有想过为何子线程中调用了loop后,进入了死循环但仍然不影响线程后面代码的执行?贴上两个链接:

下面贴上我的一些测试,用以帮助理解,先说结论:Looper.loop方法是会阻塞运行的,即loop方法后面的代码在looper调用quit之前是不会执行的。见下面测试:

public class MainActivity extends AppCompatActivity {

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

        final Thread1 t1=new Thread1();
        t1.start();

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Message message = new Message();
                message.setTarget(t1.handler);
                message.what=10;
                t1.handler.sendMessage(message);
            }
        },"thread2");
        t2.start();
    }
    class Thread1 extends Thread{
        int i=0;
        Handler handler;
        @Override
        public void run() {
            Looper.prepare();
            handler = new Handler(Looper.myLooper()) {
                @Override
                public void handleMessage(Message msg) {
                    System.out.println("ssssssssss==================="+i);
                    Looper.myLooper().quit();
                }
            };
            i=5;
            Looper.loop();
            i=100;
//            System.out.println("ssssssssss==================="+i);
        }
    }
}

执行结果如下:

04-16 20:33:44.368 4852-4885/com.zerastudio.test0416 I/System.out: ssssssssss===================5

去掉最后一行的注释后,执行结果:

04-16 20:34:58.651 6289-6321/com.zerastudio.test0416 I/System.out: ssssssssss===================5
04-16 20:34:58.651 6289-6321/com.zerastudio.test0416 I/System.out: ssssssssss===================100

足以说明了Looper调用了loop后会阻塞执行的,只有在调用了quit后才会继续往后执行。稍后会对ActivityThread进行研究,而Activity的各个生命周期均是从Looper的loop方法中开始被调用的。

Handler原理

在子线程中,通过目标线程的handler.obtainMessage,得到一个以目标线程handler作为target的message后,设置message信息,再用handler.send发送,也就是调用handler持有的messageQueue(来自Looper)的enqueueMessage插入到队列里,结合上面说的机制,唤醒loop,又转到了目标线程Handler的dispatchMessage方法里,于是切换了线程,就可以完成指定的动作了。

Message.obtain和new Message区别

Message维护了一个全局的messagePool,默认大小好像是50,回收利用对内存的消耗更小也更快。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值