Handler+Looper+Message心得体会

本文深入探讨了Android中Handler的工作原理,解释了如何在主线程与子线程间发送消息,并详细解析了Handler、Looper和Message机制。此外,还介绍了主线程中Looper的自动准备过程及其与Handler的绑定方式。

前言:我们知道Android是基于Dalvik虚拟机的,Android所有组件都是在一个进程当中的,而这个进程当中有一个主线程,用来处理UI的更新,所以我们也叫做UI线程。为了用户体验,在Android4.0以后就不允许在主线程中做耗时操作。一切的耗时操作都放到了子线程中,那么子线程怎么通知界面进行更新呢?Android中有个常用的办法,就是通过Handler类来传递子线程到主线程的消息,从而通知主线程更新界面。那么主线程是否可以向子线程发送消息呢?

我们先尝试向子线程给主线程发送消息的方式在子线程中创建一个handler,接受来自UI线程的消息,代码如下:

public class MainActivity extends Activity {

    private Handler handler;
    private final int MESSAGE_TAG=0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new myThread().start();//启动子线程
    }

    public  void sendMessageToThread(View view){

        //主线程向子线程发送消息
        String str="我是主线程发送过来的消息";
        handler.obtainMessage(MESSAGE_TAG,str).sendToTarget();
    }
    private class myThread extends Thread{
        @Override
        public void run() {
            super.run();
            handler=new Handler(){
                @Override
                public void handleMessage(Message msg) {
                    switch (msg.what){
                        case MESSAGE_TAG:
                            Toast.makeText(MainActivity.this,"主线程发送给子线程的消息为:"+(String)msg.obj,
                                    Toast.LENGTH_SHORT).show();
                            break;
                    }
                }
            };
        }
    };
}

运行程序会报一下错误:


我们可以看到,在线程中不调用Looper.prepare()方法,是不能创建handler对象的。

可是我们在UI线程中也没有调用Looper.prepare()方法呀,为什么没有报错呢?

查看源码可以知道,主线程中有个ActivityThread类,程序的入口就是该类中的main()方法。main的源码如下:

分析源码可以知道,main()方法中调用prepareMain()为UI线程创建一个消息队列(MessageQueue),然后创建一个ActivityThread对象,在ActivityThread的初始化代码中会创建一个H(Handler)对象和一个ApplicationThread(Binder)对像。


我们可以看到Handler通过mLooper = Looper.myLooper();绑定到线程的当前Looper上去,同时Handler通过mQueue =mLooper.mQueue;获得线程的消息队列。此时,Handler就绑定到创建此Handler对象的线程的消息队列上了。

接着UI主线程调用Looper.loop()方法进入消息循环体,进入后就会不断地从消息队列中读取并处理消息。看看loop()的源码。


loop()方法中通过msg.next()获取下一条需要处理的消息。当msg!=null && msg.target!=null时,调用msg.target.dispatchMessage(msg)分发消息,分发完成之后就通过msg.recycle()回收消息。msg.target获取的就是绑定到当前消息队列上的handler。看看dispatchMessage(msg)方法。

public void dispatchMessage(Message msg) {  

        if (msg.callback != null) {  

          handleCallback(msg);  

        } else {  

            if (mCallback != null) { 

                if (mCallback.handleMessage(msg)) {  

                    return;  

                }  

            }  

            handleMessage(msg);  

        }  

   }  

通常我们在使用的时候,就会重写handler中的handleMessage(msg)方法来处理消息。

这样Handler+Looper+Message的机制就理清楚了。所以其实UI线程中也是有looper.prepare()和looper.loop()方法,只是main()方法已经做好了,但是我们自己new的子线程就需要我们自己调用这两个方法。主线程给子线程发送消息正确的写法为:


备注:此文章是本人查看了相关源码,也看了一些大牛们的博客之后的一点心得体会,主要是为了加强理解。谢谢那些无私奉献的博主们!!!!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值