转载:android笔记--android中的多线程--Handler, Looper, MessageQueue, Message类

什么时候使用多线程:

1. 耗时操作使用多线程, 耗时操作放在UI线程中会导致用户的操作无法得到响应.

2. 阻塞操作使用多线程, 理由同上.

3. 多核CUP的设备使用多线程, 可以有效提高CPU的利用率.

4. 并行操作使用多线程.

android中的多线程模型主要涉及的类有:Looper, Handler, MessageQueue, Message等.

一:Looper类:

 1 static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
 2     private static Looper sMainLooper;  // guarded by Looper.class
 3
 4     final MessageQueue mQueue;
 5     final Thread mThread;
 6 public static void loop() {
 7         final Looper me = myLooper();
 8         if (me == null) {
 9             throw new RuntimeException("No Looper; Looper.prepare() wasn‘t called on this thread.");
10         }
11         final MessageQueue queue = me.mQueue;
12
13         // Make sure the identity of this thread is that of the local process,
14         // and keep track of what that identity token actually is.
15         Binder.clearCallingIdentity();
16         final long ident = Binder.clearCallingIdentity();
17
18         for (;;) {
19             Message msg = queue.next(); // might block
20             if (msg == null) {
21                 // No message indicates that the message queue is quitting.
22                 return;
23             }
24
25             // This must be in a local variable, in case a UI event sets the logger
26             Printer logging = me.mLogging;
27             if (logging != null) {
28                 logging.println(">>>>> Dispatching to " + msg.target + " " +
29                         msg.callback + ": " + msg.what);
30             }
31
32             msg.target.dispatchMessage(msg);//超级重要
33
34             if (logging != null) {
35                 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
36             }
37
38             // Make sure that during the course of dispatching the
39             // identity of the thread wasn‘t corrupted.
40             final long newIdent = Binder.clearCallingIdentity();
41             if (ident != newIdent) {
42                 Log.wtf(TAG, "Thread identity changed from 0x"
43                         + Long.toHexString(ident) + " to 0x"
44                         + Long.toHexString(newIdent) + " while dispatching to "
45                         + msg.target.getClass().getName() + " "
46                         + msg.callback + " what=" + msg.what);
47             }
48
49             msg.recycle();
50         }
51     }
52 public void quit() {
53         mQueue.quit(false);
54     }
55 public void quitSafely() {//最好用此方法
56         mQueue.quit(true);
57     }

Looper类用来创建消息队列. 每个线程最多只能有一个消息队列:Looper唯一的构造方法如下

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

android中UI线程默认具有消息队列, 但非UI线程在默认情况下是不具备消息队列的. 如果需要在非UI线程中开启消息队列, 需要调用Looper.prepare()方法, 在该方法的执行过程中会创建一个Looper对象

 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     }

而Looper的构造函数中会创建一个MessageQueue instance(Looper的构造函数是私有的, 在Looper类之外无法创建其对象).

此后再为该线程绑定一个Handler instance, 然后调用Looper.loop()方法, 就可以不断的从消息队列中取出消息和处理消息了.

 1 public Handler() {
 2         this(null, false);
 3     }
 4 public Handler(Callback callback) {
 5         this(callback, false);
 6     }
 7 public Handler(Looper looper) {
 8         this(looper, null, false);
 9     }
10 public Handler(Looper looper, Callback callback) {
11         this(looper, callback, false);
12     }
13 public Handler(Callback callback, boolean async) {
14         if (FIND_POTENTIAL_LEAKS) {
15             final Class<? extends Handler> klass = getClass();
16             if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
17                     (klass.getModifiers() & Modifier.STATIC) == 0) {
18                 Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
19                     klass.getCanonicalName());
20             }
21         }
22
23         mLooper = Looper.myLooper();
24         if (mLooper == null) {
25             throw new RuntimeException(
26                 "Can‘t create handler inside thread that has not called Looper.prepare()");
27         }
28         mQueue = mLooper.mQueue;
29         mCallback = callback;
30         mAsynchronous = async;
31     }
32 public Handler(Looper looper, Callback callback, boolean async) {
33         mLooper = looper;
34         mQueue = looper.mQueue;
35         mCallback = callback;
36         mAsynchronous = async;
37     }

(创建handler的时候必须关联一个looper)

Looper.myLoop()方法可以得到线程的Looper对象, 如果为null, 说明此时该线程尚未开启消息队列.

1 public static Looper myLooper() {
2         return sThreadLocal.get();
3     }

二:Handler:

Handler类用于处理消息. 该类具有四个构造函数:(如上)

1. public Handler(). 创建好的Handler instance将绑定在代码所在的线程的消息队列上, 因此一定要确定该线程开启了消息队列, 否则程序将发生错误. 使用这个构造函数创建Handler instance, 一般来说, 我们需要重写Hanler类的handleMessage()方法, 以便在之后的消息处理时调用.

2. public Handler(Callback callback). Callback是Handler内部定义的一个接口, 因此想要使用这个构造函数创建Handler对象, 需要自定义一个类实现Callback接口, 并重写接口中定义的handleMessage()方法. 这个构造函数其实与无参的构造函数类似, 也要确保代码所在的线程开启了消息队列. 不同的是在之后处理消息时, 将优先调用callback的handleMessage()方法,返回true,则消息处理结束;返回false。则会调用Handler对象的handleMssage()方法.

1  final MessageQueue mQueue;
2  final Looper mLooper;
3  final Callback mCallback;
4  public interface Callback {
5         public boolean handleMessage(Message msg);
6     }
7  private static void handleCallback(Message message) {
8         message.callback.run();
9     }
 1 /**
 2      * Handle system messages here.
 3      */
 4     public void dispatchMessage(Message msg) {
 5         if (msg.callback != null) {
 6             handleCallback(msg);//如上的方法
 7         } else {
 8             if (mCallback != null) {
 9                 if (mCallback.handleMessage(msg)) {
10                     return;
11                 }
12             }
13             handleMessage(msg);
14         }
15     }

3. public Handler(Looper looper). 这个构造函数表示创建一个Handler instance, 并将其绑定在looper所在的线程上. 此时looper不能为null. 此时一般也需要重写Hanler类的handleMessage()方法

4. public Handler(Looper looper, Callback callback). 可以结合2和3理解.

 1  public final Message obtainMessage()
 2     {
 3         return Message.obtain(this);
 4     }
 5 private static Message getPostMessage(Runnable r) {
 6         Message m = Message.obtain();
 7         m.callback = r;
 8         return m;
 9     }
10 public final boolean post(Runnable r)
11     {
12        return  sendMessageDelayed(getPostMessage(r), 0);
13     }
14 public final boolean postAtTime(Runnable r, long uptimeMillis)
15     {
16         return sendMessageAtTime(getPostMessage(r), uptimeMillis);
17     }
18 public final boolean postDelayed(Runnable r, long delayMillis)
19     {
20         return sendMessageDelayed(getPostMessage(r), delayMillis);
21     }
22  public final boolean postAtFrontOfQueue(Runnable r)
23     {
24         return sendMessageAtFrontOfQueue(getPostMessage(r));
25     }
26  public final boolean sendMessage(Message msg)
27     {
28         return sendMessageDelayed(msg, 0);
29     }
30  public final boolean sendEmptyMessage(int what)
31     {
32         return sendEmptyMessageDelayed(what, 0);
33     }
34 public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
35         Message msg = Message.obtain();
36         msg.what = what;
37         return sendMessageDelayed(msg, delayMillis);
38     }
39 public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
40         Message msg = Message.obtain();
41         msg.what = what;
42         return sendMessageAtTime(msg, uptimeMillis);
43     }
44 //Handler所有post、send方法,最后调的都是此方法...
45 public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
46         MessageQueue queue = mQueue;
47         if (queue == null) {
48             RuntimeException e = new RuntimeException(
49                     this + " sendMessageAtTime() called with no mQueue");
50             Log.w("Looper", e.getMessage(), e);
51             return false;
52         }
53         return enqueueMessage(queue, msg, uptimeMillis);
54     }
55 //入队,其实调的是MessageQueue的入队方法
56 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
57         msg.target = this;
58         if (mAsynchronous) {
59             msg.setAsynchronous(true);
60         }
61         return queue.enqueueMessage(msg, uptimeMillis);
62     }
63 //Handler的hasMessage、removeCallback是MessageQueue的方法
64  public final void removeMessages(int what) {
65         mQueue.removeMessages(this, what, null);
66     }
67  public final void removeCallbacksAndMessages(Object token) {
68         mQueue.removeCallbacksAndMessages(this, token);
69     }
70 public final boolean hasMessages(int what) {
71         return mQueue.hasMessages(this, what, null);
72     }
73 public final boolean hasCallbacks(Runnable r) {
74         return mQueue.hasMessages(this, r, null);
75     }

三,MessageQueue:

MessageQueue类用于表示消息队列. 队列中的每一个Message都有一个when字段, 这个字段用来决定Message应该何时出对处理. 消息队列中的每一个Message根据when字段的大小由小到大排列, 排在最前面的消息会首先得到处理, 因此可以说消息队列并不是一个严格的先进先出的队列.

方法主要有:

Message next() {...}
void quit(boolean safe) {
        if (!mQuitAllowed) {
            throw new RuntimeException("Main thread not allowed to quit.");
        }

        synchronized (this) {
            if (mQuitting) {
                return;
            }
            mQuitting = true;

            if (safe) {
                removeAllFutureMessagesLocked();
            } else {
                removeAllMessagesLocked();
            }

            // We can assume mPtr != 0 because mQuitting was previously false.
            nativeWake(mPtr);
        }
    }
//入队
 boolean enqueueMessage(Message msg, long when) {...}
//判断消息队列中是否包含某个消息
boolean hasMessages(Handler h, int what, Object object) {...}
//将某个消息从队列中移出去,该消息被回收到消息池中了
void removeMessages(Handler h, int what, Object object) {...}

四:Message:

Message类用于表示消息. Message对象可以通过arg1, arg2, obj字段和setData()携带数据, 此外还具有很多字段. when字段决定Message应该何时出对处理, target字段用来表示将由哪个Handler对象处理这个消息, next字段表示在消息队列中排在这个Message之后的下一个Message, callback字段如果不为null表示这个Message包装了一个runnable对象, what字段表示code, 即这个消息具体是什么类型的消息. 每个what都在其handler的namespace中, 我们只需要确保将由同一个handler处理的消息的what属性不重复就可以.

 1     public int what;
 2     public int arg1;
 3     public int arg2;
 4     public Object obj;
 5     public Messenger replyTo;
 6     /** If set message is in use */
 7     static final int FLAG_IN_USE = 1 << 0;
 8     /** If set message is asynchronous */
 9    static final int FLAG_ASYNCHRONOUS = 1 << 1;
10     /** Flags to clear in the copyFrom method */
11    static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;
12     int flags;
13     long when;
14     Bundle data;
15      Handler target;
16      Runnable callback;
17     // sometimes we store linked lists of these things
18     Message next;
19
20     private static final Object sPoolSync = new Object();
21     private static Message sPool;
22     private static int sPoolSize = 0;
23
24     private static final int MAX_POOL_SIZE = 50;
 1 public static Message obtain() {
 2         synchronized (sPoolSync) {
 3             if (sPool != null) {
 4                 Message m = sPool;
 5                 sPool = m.next;
 6                 m.next = null;
 7                 sPoolSize--;
 8                 return m;
 9             }
10         }
11         return new Message();
12     }
13 public static Message obtain(Message orig) {
14         Message m = obtain();
15         m.what = orig.what;
16         m.arg1 = orig.arg1;
17         m.arg2 = orig.arg2;
18         m.obj = orig.obj;
19         m.replyTo = orig.replyTo;
20         if (orig.data != null) {
21             m.data = new Bundle(orig.data);
22         }
23         m.target = orig.target;
24         m.callback = orig.callback;
25
26         return m;
27     }
28 public static Message obtain(Handler h) {
29         Message m = obtain();
30         m.target = h;
31
32         return m;
33     }
34 ......
35 void clearForRecycle() {
36         flags = 0;
37         what = 0;
38         arg1 = 0;
39         arg2 = 0;
40         obj = null;
41         replyTo = null;
42         when = 0;
43         target = null;
44         callback = null;
45         data = null;
46     }
47 public void recycle() {
48         clearForRecycle();
49
50         synchronized (sPoolSync) {
51             if (sPoolSize < MAX_POOL_SIZE) {
52                 next = sPool;
53                 sPool = this;
54                 sPoolSize++;
55             }
56         }
57     }
58 public void copyFrom(Message o)
59 public long getWhen()
60 public void setTarget(Handler target)
61 public Handler getTarget()
62 public Runnable getCallback()
63 public Bundle getData() {
64         if (data == null) {
65             data = new Bundle();
66         }
68         return data;
69     }
70 public Bundle peekData() {
71         return data;
72     }
73 public void setData(Bundle data)
74  public void sendToTarget()

将消息压入消息队列: Message对象的target字段关联了哪个线程的消息队列, 这个消息就会被压入哪个线程的消息队列中.

1. 调用Handler类中以send开头的方法可以将Message对象压入消息队列中, 调用Handler类中以post开头的方法可以将一个runnable对象包装在一个Message对象中, 然后再压入消息队列, 此时入队的Message其callback字段不为null, 值就是这个runnable对象. 调用Handler对象的这些方法入队的Message, 其target属性会被赋值为这个handler对象.

2. 调用Message对象的sendToTarget()方法可以将其本身压入与其target字段(即handler对象)所关联的消息队列中.

将未来得及处理的消息从消息队列中删除:

调用Handler对象中以remove开头的方法就可以.

从消息队列中取出消息并处理消息: 所有在消息队列中的消息, 都具有target字段. 消息是在target所关联的线程上被取出和处理的.

 1 /**
 2      * Handle system messages here.
 3      */
 4     public void dispatchMessage(Message msg) {
 5         if (msg.callback != null) {
 6             handleCallback(msg);
 7         } else {
 8             if (mCallback != null) {
 9                 if (mCallback.handleMessage(msg)) {
10                     return;
11                 }
12             }
13             handleMessage(msg);
14         }
15     }

1. 如果取出的Message对象的callback字段不为null, 那么就调用callback字段的run()方法(callback字段的类型是runnable). 注意此时并不开启一个新的线程运行run()方法, 而是直接在handler对象(即Message的target字段)所关联的线程上运行.

2. 如果取出的Message对象的callback字段为null, 且Handler对象中的callback字段也为null, 那么这个消息将由Handler对象的handleMessage(msg)方法处理. 注意Message对象的callback字段是Runnable类型的而Handler对象的callback字段是Callback类型的, Handler对象的callback字段是在创建Handler instance的时候指定的, 如果没有指定则这个字段为null, 详见Handler类的四个构造方法.

3. 如果取出的Message对象的callback字段为null, 且Handler对象中的callback字段不为null, 那么这个消息将由Handler对象中的callback字段的handleMessage方法优先处理.

线程间通信: 有了以上的叙述, 线程间的通信也就好理解了. 假如一个handler关联了A线程上的消息队列, 那么我们可以在B线程上调用handler的相关方法向A线程上的消息队列压入一个Message, 这个Message将在A线程上得到处理.

转载:android笔记--android中的多线程--Handler, Looper, MessageQueue, Message类

时间: 2024-08-14 05:42:16

转载:android笔记--android中的多线程--Handler, Looper, MessageQueue, Message类的相关文章

Android消息传递源码理解。Handler,Looper,MessageQueue,Message

Android中消息传递模块差不多看了好几次,虽然每次看的方式都差不多但是还是发觉的到每次看了之后,理解的更清晰一点. 关于这个模块的文章数不胜数,但是最重要的还是自己动手理解一遍更好. 会牵扯到的几个类: Handler.java  , Looper.java , MessageQueue.java , Message.java 源代码路径: xxx/frameworks/base/core/java/android/os  看的过程中你会发现高版本和低版本系统代码有些地方比较大的差距.从中我

Android多线程之图解Handler Looper MessageQueue Message

Android中的多线程可以有多种实现方式,前面我们已经讲过了封装程度较高异步任务(AnsyncTask),这一节我们来看看较为灵活的方式:Handler Looper MessageQueue Message. Message:用于线程之间传递信息,发送的消息放入目标线程的MessageQueue中. MessageQueue:用于简化线程之间的消息传递,MessageQueue接受发送端的Message,并作为消息处理端的输入源.每个线程只有一个实例. Handler:用于处理Message

线程间通信: Handler , Looper, MessageQueue, Message (完结)

概述:    为了 线程间 通信方便, Handler 机制 通过 Handler 和 Looper, MessageQueue, Message 这些 类 之间的协作, 简化 多线程的开发.  线程的交互 会被封装 到 Message 中, 然后 通过 Handler 的方法 把 消息 放到 MessageQueue 消息队列中, 实现 Handler 机制的线程 都会 调用 Looper 的 loop() 方法, 则 Looper 作为 消息分发者的 作用就体现出来了.  loop() 方法

Android中的Handler, Looper, MessageQueue和Thread

Android中的Handler, Looper, MessageQueue和Thread 前几天,和同事探讨了一下Android中的消息机制,探究了消息的发送和接收过程以及与线程之间的关系.虽然我们经常使用这些基础的东西,但对于其内部原理的了解,能使我们更加容易.合理地架构系统,并避免一些低级错误. 对于这部分的内容,将分成4小节来描述: 1.职责与关系 2.消息循环 3.线程与更新 4.几点小结 ------------------------------------------------

Android笔记——Android中数据的存储方式(二)

我们在实际开发中,有的时候需要储存或者备份比较复杂的数据.这些数据的特点是,内容多.结构大,比如短信备份等.我们知道SharedPreferences和Files(文本文件)储存这种数据会非常的没有效率.如果学过JavaWeb的朋友,首先可能想到的是数据库.当然了数据库是一个方案,那么是否还有其他的解决方案呢?今天我们在讲下Android笔记——Android中数据的存储方式(一) 提到的除了SharedPreferences和Files(文本文件)以外的其他几种数据储存方式:xml文件.SQL

Android异步处理三:Handler+Looper+MessageQueue深入详解

Android Loop&Handle学习总结 - New Start - 博客频道 - CSDN.NET ?????? 昨晚偷懒,这篇博客只写了一个标题,今天早晨一看,还有15的阅读量.实在是对不起那些同学.......换了是我,也会BS这样的LZ吧!sorry 啦 -------------------------------------------------------------------------------------------------------------------

Android笔记——Android中数据的存储方式(三)

Android系统集成了一个轻量级的数据库:SQLite,所以Android对数据库的支持很好,每个应用都可以方便的使用它.SQLite作为一个嵌入式的数据库引擎,专门适用于资源有限的设备上适量数据存取,现在的主流移动设备像Android.iPhone等都使用SQLite作为复杂数据的存储引擎,并且它是以手机内存为储存的. 那么,实际开发项目中有大量数据需要读写,并且需要面临大量用户的并发储存的情况呢.就不应该把数据存放在手机等移动设备的SQLite数据库里,移动设备的储存能力和计算能力都不足以

自学Android笔记——Activity中的数据传递案例(用户注册)

1.创建程序activity_main: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <Line

自学Android笔记——Activity中的回传数据案例(装备选择)

1.创建程序: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:conte