Android Handler 消息机制分析(一)

        Handler,Message,MessageQueue,Looper,android一种消息处理机制,在android开发中经常会用到,当Handler创建后,会被绑定到它所在的线程上,处理消息的成员及其功能如下:

        Handler:发送一个消息(Message)去做特定任务

        Message:代表一个要处理的任务;

        MessageQueueMessage的队列;

        Looper:负责循环Message队列,取出Message又传给Handler处理。

它们之间关系如下:

        每个线程中只有一个Looper,由ThreadLocal维护;

        每个Looper中只有一个MessageQueue,因此一个线程中只有一个MessageQueue

        每个MessageQueue中可以有多个Message

        每个线程中可以有多个Handler

四者关系如下图:

接下来我们以开发中使用时的顺序来分析它们之间的关系。

1.Looper

        Looper,就是不断循环读取消息给Handler。在开发过程中,更多的是在主线程中对Handler进行实例化,然后就可以调用sendMessage()方法发送消息了,不需要对Looper做额外的处理,但是如果我们在子线程进行实例化Handler时,则必须在实例化Handler之前对Looper做如下的操作:

class MyThread extends Thread{
    @Override
    public void run() {
        //为该线程创建一个Looper
        Looper.prepare();
        //实例化Handler
        mHandler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
            }
        };
        //不断循环读取Message
        Looper.loop();
    }
}
        至于为什么在子线程中必须进行这样的操作,而在主线程就不需要这样的操作呢?这就先得从 Handler 说起了。

1.1.子线程中Looper的获取

        Handler的构造方法如下:

public Handler() {
    this(null, false);
}

直接看它另一个重载构造方法:

public Handler(Callback callback, boolean async) {
    if (FIND_POTENTIAL_LEAKS) {
        final Class<? extends Handler> klass = getClass();
        if ((klass.isAnonymousClass() || klass.isMemberClass() 
               || klass.isLocalClass()) &&
                (klass.getModifiers() & Modifier.STATIC) == 0) {
            Log.w(TAG, "The following Handler class should be 
                    static or leaks might occur: " + klass.getCanonicalName());
        }
    }
   //获取当前线程的Looper
    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

        这里很明显了,在Handler实例化时,会首先获取当前线程的Looper,如果不存在Looper,则抛出Runtime异常,注意了,这里是当前线程,这是什么意思?下面进行分析

        再来看看Looper中的两个静态方法干了什么,prepare()方法如下:

private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    sThreadLocal.set(new Looper(quitAllowed));
}      

        在prepare()方法中,获取了Looper对象,并且维护了一个ThreadLocal存放每个线程的Looper对象,通过ThreadLocal将线程和Looper进行了绑定,从而解决了多线程问题,保证了每个线程只有一个Looper对象。因此,如果在子线程中不显示调用prepare()方法,则由于该线程中没有Looper对象,从而报出异常:Can't create handler inside thread that has 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值