Android异步消息处理之Looper,Handler,Message,MessageQueue
2016-05-29 10:19
375 查看
android为我们提供了很多办法。
1)、handler和message机制:通过显示的抛出、捕获消息与ui进行交互;
2)、Activity.runOnUiThread(Runnable):如果当前线程为ui线程,则立即执行;否则,将参数中的线程操作放入到ui线程的事件队列中,等待执行。
3)、View.post(Runnable):将操作放入到message队列中,如果放入成功,该操作将会在ui线程中执行,并返回true,否则返回false
4)、View.postDelayed(Runnable, long)跟第三条基本一样,只不过添加了一个延迟时间。
5)、android1.5以后为我们提供了一个工具类来搞定这个问题AsyncTask.
异步消息线程不同一般线程的是,它的线程run方法有一个无限循环,每循环一次,从其内部的消息队列中取出一个消息并调用回调函数进行处理。如果消息队列为空,线程暂停,直到消息队列中有新的消息。
(一)Looper,Handler,Message,MessageQueue
1、 Looper主要作用就是产生及管理MessageQueue,Looper是整个消息循环的基础。某个线程调用Looper的prepare方法时,prepare方法内部会生成一个MessageQueue,而且一个线程最多只会有一个Looper实例,同时一个Looper实例也只有一个MessageQueue。在主线程使用Handler时不需要调用Looper.prepare(),Looper.loop(),因为主线程的main()方法中已经调用 Looper.prepareMainLooper()来产生了一个MessageQueue,同时调用了Looper.loop()来进行循环处理。但是在非主线程使用Handler则必须要调用这两个方法。
2、 调用looper的loop()方法时,loop()方法内部会不断从MessageQueue中去取Message,同时调用Handler 的dispatchMessage方法把消息交给Handler处理。
3、 Handler的作用一是把Message发送到MessageQueue中,二是处理MessageQueue中的Message(由Looper从MessageQueue中取出Message交给Handler处理)。
4、 Message 代表一个行为(what)或者一串动作(Runnable)
5、 每个线程可以包含多个Handler,Handler将Message发送到MessageQueue中,调用sendMessage方法,其内部又调用enqueueMessage方法将Message加入到MessageQueue中。而enqueueMessage将此Handler赋值给Message的target变量,这也就将Message与Handler绑定在一起了,因为是哪儿Handler发送的Message就由哪个Handler处理,也就是由创建Handler的线程处理。
6 、 Messenger可以翻译为信使,可以实现进程间通信(IPC),Messenger采用一个单线程来处理所有的消息,而且进程间的通信都是通过发消息来完成的,感觉不能像AIDL那样直接调用对方的接口方法(具体有待考证),这是其和AIDL的主要区别,也就是说Messenger无法处理多线程,所有的调用都是在一个线程中串行执行的。Messenger的典型代码是这样的:new Messenger(service).send(msg),它的本质还是调用了Handler的sendMessage方法
4000
下面是Looper的主要代码片段:
下面是Message的部分代码:
下面是Handler的部分代码:
Handler的post()方法
View的post()方法
Activity的runOnUiThread()方法
我们先来看下Handler中的post()方法,代码如下所示:
原来这里还是调用了sendMessageDelayed()方法去发送一条消息啊,并且还使用了getPostMessage()方法将Runnable对象转换成了一条消息,我们来看下这个方法的源码:
在这个方法中将消息的callback字段的值指定为传入的Runnable对象。咦?这个callback字段看起来有些眼熟啊,喔!在Handler的dispatchMessage()方法中原来有做一个检查,如果Message的callback等于null才会去调用handleMessage()方法,否则就调用handleCallback()方法。那我们快来看下handleCallback()方法中的代码吧:
也太简单了!竟然就是直接调用了一开始传入的Runnable对象的run()方法。因此在子线程中通过Handler的post()方法进行UI操作就可以这么写:
虽然写法上相差很多,但是原理是完全一样的,我们在Runnable对象的run()方法里更新UI,效果完全等同于在handleMessage()方法中更新UI。
然后再来看一下View中的post()方法,代码如下所示:
原来就是调用了Handler中的post()方法,我相信已经没有什么必要再做解释了。
最后再来看一下Activity中的runOnUiThread()方法,代码如下所示:
如果当前的线程不等于UI线程(主线程),就去调用Handler的post()方法,否则就直接调用Runnable对象的run()方法。还有什么会比这更清晰明了的吗?
1)、handler和message机制:通过显示的抛出、捕获消息与ui进行交互;
2)、Activity.runOnUiThread(Runnable):如果当前线程为ui线程,则立即执行;否则,将参数中的线程操作放入到ui线程的事件队列中,等待执行。
3)、View.post(Runnable):将操作放入到message队列中,如果放入成功,该操作将会在ui线程中执行,并返回true,否则返回false
4)、View.postDelayed(Runnable, long)跟第三条基本一样,只不过添加了一个延迟时间。
5)、android1.5以后为我们提供了一个工具类来搞定这个问题AsyncTask.
异步消息线程不同一般线程的是,它的线程run方法有一个无限循环,每循环一次,从其内部的消息队列中取出一个消息并调用回调函数进行处理。如果消息队列为空,线程暂停,直到消息队列中有新的消息。
(一)Looper,Handler,Message,MessageQueue
1、 Looper主要作用就是产生及管理MessageQueue,Looper是整个消息循环的基础。某个线程调用Looper的prepare方法时,prepare方法内部会生成一个MessageQueue,而且一个线程最多只会有一个Looper实例,同时一个Looper实例也只有一个MessageQueue。在主线程使用Handler时不需要调用Looper.prepare(),Looper.loop(),因为主线程的main()方法中已经调用 Looper.prepareMainLooper()来产生了一个MessageQueue,同时调用了Looper.loop()来进行循环处理。但是在非主线程使用Handler则必须要调用这两个方法。
2、 调用looper的loop()方法时,loop()方法内部会不断从MessageQueue中去取Message,同时调用Handler 的dispatchMessage方法把消息交给Handler处理。
3、 Handler的作用一是把Message发送到MessageQueue中,二是处理MessageQueue中的Message(由Looper从MessageQueue中取出Message交给Handler处理)。
4、 Message 代表一个行为(what)或者一串动作(Runnable)
5、 每个线程可以包含多个Handler,Handler将Message发送到MessageQueue中,调用sendMessage方法,其内部又调用enqueueMessage方法将Message加入到MessageQueue中。而enqueueMessage将此Handler赋值给Message的target变量,这也就将Message与Handler绑定在一起了,因为是哪儿Handler发送的Message就由哪个Handler处理,也就是由创建Handler的线程处理。
6 、 Messenger可以翻译为信使,可以实现进程间通信(IPC),Messenger采用一个单线程来处理所有的消息,而且进程间的通信都是通过发消息来完成的,感觉不能像AIDL那样直接调用对方的接口方法(具体有待考证),这是其和AIDL的主要区别,也就是说Messenger无法处理多线程,所有的调用都是在一个线程中串行执行的。Messenger的典型代码是这样的:new Messenger(service).send(msg),它的本质还是调用了Handler的sendMessage方法
4000
下面是Looper的主要代码片段:
public final class Looper { // sThreadLocal.get() will return null unless you've called prepare(). static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); private static Looper sMainLooper; // guarded by Looper.class final MessageQueue mQueue; final Thread mThread; public static void prepare() { prepare(true); } 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)); } private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mRun = true; mThread = Thread.currentThread(); } 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; // Make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } 。。。省略 msg.target.dispatchMessage(msg);//msg.target就是Handler 。。。省略 } }
下面是Message的部分代码:
public final class Message implements Parcelable { public int what; public int arg1; public int arg2; public Object obj; public Messenger replyTo; int flags; long when; Bundle data; Handler target; Runnable callback; Message next; private static Message sPool; private static int sPoolSize = 0; private static final int MAX_POOL_SIZE = 50; }
下面是Handler的部分代码:
final MessageQueue mQueue; final Looper mLooper; public Handler() { this(null, false); } public Handler(Callback callback, boolean async) { 。。。省略 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; } public void dispatchMessage(Message msg) { if (msg.callback != null) {//msg.callback是Runnable对象, 直接调用msg.callback.run(); handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
Handler的post()方法
View的post()方法
Activity的runOnUiThread()方法
我们先来看下Handler中的post()方法,代码如下所示:
public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); }
原来这里还是调用了sendMessageDelayed()方法去发送一条消息啊,并且还使用了getPostMessage()方法将Runnable对象转换成了一条消息,我们来看下这个方法的源码:
private final Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }
在这个方法中将消息的callback字段的值指定为传入的Runnable对象。咦?这个callback字段看起来有些眼熟啊,喔!在Handler的dispatchMessage()方法中原来有做一个检查,如果Message的callback等于null才会去调用handleMessage()方法,否则就调用handleCallback()方法。那我们快来看下handleCallback()方法中的代码吧:
private final void handleCallback(Message message) { message.callback.run(); }
也太简单了!竟然就是直接调用了一开始传入的Runnable对象的run()方法。因此在子线程中通过Handler的post()方法进行UI操作就可以这么写:
public class MainActivity extends Activity { private Handler handler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); handler = new Handler(); new Thread(new Runnable() { @Override public void run() { handler.post(new Runnable() { @Override public void run() { // 在这里进行UI操作 } }); } }).start(); } }
虽然写法上相差很多,但是原理是完全一样的,我们在Runnable对象的run()方法里更新UI,效果完全等同于在handleMessage()方法中更新UI。
然后再来看一下View中的post()方法,代码如下所示:
public boolean post(Runnable action) { Handler handler; if (mAttachInfo != null) { handler = mAttachInfo.mHandler; } else { ViewRoot.getRunQueue().post(action); return true; } return handler.post(action); }
原来就是调用了Handler中的post()方法,我相信已经没有什么必要再做解释了。
最后再来看一下Activity中的runOnUiThread()方法,代码如下所示:
public final void runOnUiThread(Runnable action) { if (Thread.currentThread() != mUiThread) { mHandler.post(action); } else { action.run(); } }
如果当前的线程不等于UI线程(主线程),就去调用Handler的post()方法,否则就直接调用Runnable对象的run()方法。还有什么会比这更清晰明了的吗?
相关文章推荐
- 设置tableView固定位置和尺寸---automaticallyAdjustsScrollViewInsets
- "\\ndk-build.cmd" clean Cannot run program "\ndk-build.cmd": Launching failed解决方法
- 2016 UESTC Traing Search Algorithm &String Problem N 简单的双向搜索
- [疯狂Java]集合:Deque(双端队列)以及两个实现(ArrayDeque、LinkedList)、Stack(摒弃)、各线性表性能分析
- GUID
- iOS悬浮窗UIBezierPath圆形扩散转场动画
- UItableView与UICollectionView
- DB_NAME、DBID、DB_UNIQUE_NAME、SERVICE_NAME、SID、INSTANCE_NAME、GLOBAL_DATABASE_NAME
- LeetCode - UniquePaths
- Java建造者模式(Builder模式)
- HDU1297 Children’s Queue
- SPOJ - QTREE Query on a tree 树链剖分
- Your build settings specify a provisioning profile with the UUID “”, however, no such provisioning p
- Volley用StringRequest的post方法传参问题
- Your build settings specify a provisioning profile with the UUID, no provisioning profile was
- 1019: Arithmetic Sequence
- 安卓UI设计中fill_parent、wrap_content和match_parent的区别
- Chrome Extension 的 webRequest模块的解读
- 【Java】斐波那契数列(Fibonacci Sequence、兔子数列)的3种计算方法(递归实现、递归值缓存实现、循环实现、尾递归实现)
- UIsSearchBar 与tableViewController