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

来源:互联网 发布:直播免费刷人气软件 编辑:程序博客网 时间:2024/05/16 16:56

这一章主要讲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后,进入了死循环但仍然不影响线程后面代码的执行?贴上两个链接:

  • https://www.zhihu.com/question/34652589
  • http://blog.csdn.net/ashqal/article/details/32107099

下面贴上我的一些测试,用以帮助理解,先说结论: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===================504-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,回收利用对内存的消耗更小也更快。

0 0