Handler机制

Hanlder作用

  • handler是更新UI界面的机制(线程间的信息传递),也是消息处理机制,可以用来发送和处理消息

Handler的使用

Handler handelr = new Handler(){
 @Override
  public void handleMessage(final Message msg) {
    //这里接受并处理消息
  }
};

实例一个Handler对象,并重写handlerMessage()方法,然后再调用他的send和post系列的方法,还支持延迟消息

Handler分析

我们可以看下创建Handler的源码:

   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());
            }
        }

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

Looper

从这里我们可以看到创建Handler的时候,Hanlder都会先去检查Looper是否为空。如果为空的话则会抛出异常。所以在创建Handler之前必须要先创建Looper

不过在平常创建Handler的时候,通常没有创建Looper。在使用的时候也没看见有异常,这个是因为主线程已经帮我们创建了Looper。在后面会说到。

创建一个完整的Handler是这样的:

class LooperThread extends Thread {
            public Handler mHandler;
                public void run() {
                   Looper.prepare();
                   mHandler = new Handler() {
                        public void handleMessage(Message msg) {
                           // process incoming messages here
                        }
                    };
                    //开始循环取出消息
                    Looper.loop();
                }
        }

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));
    }

Looper提供Looper.prepare();来创建Looper,并且通过ThreadLocal来与当前的线程进行绑定

Looper.loop();

    /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

       //...

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // This must be in a local variable, in case a UI event sets the logger
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

           //...
            try {
                msg.target.dispatchMessage(msg);
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            //...

            msg.recycleUnchecked();
        }
    }

可以看出Looper.loop()是个死循环,不停的通过queue.next()获取消息,并通过msg.target.dispatchMessage(msg)将消息回调到Handler,msg.target就是消息的Handler对象。

queue.next()是MessageQueue中获取Message的方法。

MessageQueue

我们都知道发送消息是通过Handler的send以及post系类的方法。但是我们一步步往下看不难发现。其实都是执行了MessageQueue的enqueueMessage(Message msg, long when);方法。

从以上可以看出,MessageQueue是负责Message消息的管理以及处理

Handler图解

image

image

线程的切换

通常会被问到Handler是怎样实现线程切换的,其实将其中的方法走向列出来,就很容易发现啦。

  1. 异步线程调用主线中Hander的send或者post方法
  2. MessageQueue收到消息,并存起来
  3. Looper.loop()查询消息
  4. MessageQueue.next();查询消息
  5. Message.target.dispatchMessage()将查询的消息发送出去
  6. 消息回到Handler.handleMessage()。

看到这里就发现消息回到主线程了,看到这里发现Handler.handleMessage()所在的线程最终还是由Looper.loop() 的线程所决定

前面说到我们平时写Handler时并没有创建Looper。其实是我们的UI线程已经帮我们创建了。在创建Activity的时候就已经帮创建了一个主线程。

了解更多的关于Android主线程(ActivityThread)

Message的创建

Android给message设置了回收机制,在创建Message的时候尽量复用,减少内存的消耗。

可以Message.obtain()以及handler.obtainMessage()来获取Message对象

总结

MessageQueue 就是设计模式中的缓冲区,它扶着接收生产这发送过劳的数据先进先出的队列心事,保存所有消息。在UI线程Lopper不断的从MessageQueue取出消息执行

Looper的主要任务就是维护MessageQueue中的消息队列,它负责取出要处理的消息任务,先判断Looper是否为空,如果不为空就一直循环不断冲MessageQueue中取出消息,然后通过dispatchMessage派发出去处理

Handler负责发送以及处理消息

每个线程只能有一个Looper对象,而且是通过ThreadLocal来存放,其他线程无法访问当前的Looper。

Looper可以让一个普通的线程具有消息循环的能力。

说UI线程都默认有一个Looper对象,可以通过Looper.myLooper()获取到

在一个Looper对象可以有多个Handler

小弟能力有限,有不足之处还望指出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值