您的位置:首页 > 移动开发 > Android开发

Handler用法详解

2016-07-12 13:49 363 查看
Handler 简介:

主要作用:1>在新起的线程中发送消息

2>在主线程中(UI线程,main thread)中接收消息,并更新UI。

原因:Android4.0后,Google官方禁止在主线程中进行耗时操作,避免引起ANR,提高用户体验。假设不用Handler的话,改用加锁方案,但是稍微一想就会发现,这样的方式会无限增加代码的复杂度,增加代码的耦合,而且锁问题还会引起别的不稳定因素。

用法:

构建Handler的成员变量,重写handleMessage(android.os.Message msg)方法,开启子线程或在回调中发送消息方法一般有:sendEmptyMessage或者obtainMessage,这两者的区别主要在与obtainMessage可以避免创建对象,从而减少内存的开销。

Handler中一共涉及到四个对象:Handler、Message、Looper、MessageQueue。这四者的关系和原理:

Message:Handler发送、接受和处理的消息对象;

Looper:每个线程都有一个Looper对象,负责无限循环的去从消息队列中取消息,并将读取到的消息发送给Handler对象去处理;

MessageQueue:消息队列,它采用先进先出的方式去管理Message,程序在创建Looper对象时,会在他的构造器中创建MessageQueue,源码:

private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}


Handler:作用有两个,发送消息和处理消息,Handler发送的消息必须送到指定的MessageQueue,而MessageQueue是由Looper负责管理的,因此要想Handler正常工作,必须在当前线程中有一个Looper对象这里分为两种情况:

      1>主线程(UI线程),系统已经初始化了一个Looper对象,因此程序直接创建Handler即可

      2>程序员自己创建的子线程,这时,程序员必须创建一个Looper对象,并启动它。

    创建Looper使用:Looper.prepare(),查看源码:

1    public static void prepare() {
2         prepare(true);
3     }
4
5   private static void prepare(boolean quitAllowed) {
6         if (sThreadLocal.get() != null) {
7             throw new RuntimeException("Only one Looper may be created per thread");
8         }
9         sThreadLocal.set(new Looper(quitAllowed));
10     }
11
12   private Looper(boolean quitAllowed) {
13         mQueue = new MessageQueue(quitAllowed);
14         mThread = Thread.currentThread();
15     }


    通过方法调用,第9行创建Looper对象,创建Looper对象时同时会创建MessageQueue对象(第13行)。此外,可以看出prepare()允许一个线程最多有一个Looper被创建。

    然后调用Looper的looper()方法来启动它,looper()使用一个死循环不断取出MessageQueue中的消息,并将消息发送给对应的Handler进行处理。下面是Looper类中looper()方法的部分源码:

1 for (;;) {
2             Message msg = queue.next(); // might block
3             if (msg == null) {
4                 // No message indicates that the message queue is

quitting.
5                 return;
6             }
7
8             // This must be in a local variable, in case a UI event sets the logger
9             Printer logging = me.mLogging;
10             if (logging != null) {
11                 logging.println(">>>>> Dispatching to " + msg.target + " " +
12                         msg.callback + ": " + msg.what);
13             }
14
15             msg.target.dispatchMessage(msg);
16
17             if (logging != null) {
18                 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
19             }
20
21             // Make sure that during the course of dispatching the
22             // identity of the thread wasn't corrupted.
23             final long newIdent = Binder.clearCallingIdentity();
24             if (ident != newIdent) {
25                 Log.wtf(TAG, "Thread identity changed from 0x"
26                         + Long.toHexString(ident) + " to 0x"
27                         + Long.toHexString(newIdent) + " while dispatching to "
28                         + msg.target.getClass().getName() + " "
29                         + msg.callback + " what=" + msg.what);
30             }
31
32             msg.recycleUnchecked();
33         }


    很明显第1行用了一个死循环,第2行从queue中取出Message,第15行通过dispatchMessage(Message msg)方法将消息发送给Handler。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android Handler