Android Handler消息处理机制 一些事一些情
来源:互联网 发布:阿里云 杰出 科学家 编辑:程序博客网 时间:2024/06/03 13:18
Android消息处理机制(Handler、Looper、MessageQueue与Message)
1、Message : 消息
2、MessageQueue : 消息队列
3、Looper:消息循环,用于循环取出消息进行处理(维护消息队列)
4、Handler :Looper在MessageQueue中取出消息后对消息进行处理
我们都知道Android 的入口主程序是 ActivityThread此类的main方法,它管理应用进程的主线程的执行(相当于普通Java程序的main入口函数)。
public final class ActivityThread {..................... final Looper mLooper = Looper.myLooper();.....................public static void main(String[] args) { .......................... Looper.prepareMainLooper(); //这里是调用Looper的循环器,不断取出消息并用handler分发 Looper.loop(); ....................... }}
这就是我们入口主程序了,是不是看到了Looper,这就是对了,android消息机制默认就是主线程,不需要我们手动来启动一个Looper来建立一个主线程来更新UI,而在子线程中,我们则需要手动来开启一个Looper来开启消息循环和停止消息循环。好,我们一步步来,是不是看到了一个全局的mLooper ,通过 Looper.myLooper()的静态方法来获取一个Looper对象,源码查看:
/**Return the Looper object associated with the current thread. Returns null if the calling thread is not associated with a Looper. */返回当前线程的Looper对象,如果返回null,则说明当前线程没有相关的Looper对象。 //这个myLoope()方法,主要是获取存储在ThreadLocal的Looper对象 public static Looper myLooper() { return sThreadLocal.get(); }
再看看 Looper.prepareMainLooper()方法:
public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } }该方法是把主线程和消息序列放进Looper里面,同时把Looper放到ThreadLocal中
下面讲一下Looper类的重要的几个方法:
1、prepare()
在prepare()方法中,判断了一下为不为Null,如果当前的ThreadLocal里面有值,就会抛出异常,ThreadLocal作用是保存当前线程的变量,在这里是保存Looper对象,这说明了该方法不能调用2次,并且一个线程中只有一个Looper对象。并且实例了一个MessageQueue(消息队列)。
public static final void prepare() { //保证了Looper的唯一性 if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } //该方法是实例Looper对象,在构造方法中实例了消息队列 sThreadLocal.set(new Looper(true)); }private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mRun = true; mThread = Thread.currentThread(); }
2、loop()方法,稍微有点长……
//这个myLoope()方法,主要是获取存储在ThreadLocal的Looper对象public static Looper myLooper() { return sThreadLocal.get(); } public static void loop() {//可以看出myLooper该方法就是获取保存在ThreadLocal的Looper对象//因为可以联想到什么,我们是在prepare()方法实例Looper,并且保存到ThreadLocal中,因为,prepare()方法必须执行于loop()方法之前,否则抛出异常! final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); }//looper实例中的mQueue(消息队列),在实例Looper中,已经创建了消息队列了,在这里获取消息队列, 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; }// This must be in a local variable, in case a UI event sets the logger Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); }//取出消息的target(就是handler),执行分发消息的处理操作,//因为dispatchMessage()这个方法是Handler中的,通过Message中的Handler引用来调用该方法来处理消息,在Message中的Hnalder的引用名字就是target,哈哈哈...... msg.target.dispatchMessage(msg); if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } // Make sure that during the course of dispatching the // identity of the thread wasn't corrupted. final long newIdent = Binder.clearCallingIdentity(); if (ident != newIdent) { Log.wtf(TAG, "Thread identity changed from 0x" + Long.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to " + msg.target.getClass().getName() + " " + msg.callback + " what=" + msg.what); } //把Message对象的标记,信息置为空 msg.recycleUnchecked(); } }
好好,既然msg拿到了,也交到了Handler的手中,那么来看看Handler是怎样处理的。
public class 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()); } } //获取了当前线程保存的Looper实例,就是上面提到的。 //主要是myLooper这个方法都是获取当前的Looper实例。 mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); }/**获取了这个Looper实例中保存的MessageQueue(消息队列),上面创建Looper的时候就已经提到了,实例Looper的时候,会构建一个MessageQueue,而在消息队列中获取了Message,又通过了hanler的dispatchMessage()方法,把这个消息发送过去了,下面我们来看看dispatchMessage()这个方法,这样就handler、Looper、MessageQueue就有了关联。*/ mQueue = mLooper.mQueue;//获取上面保存的消息队列 mCallback = callback;//这个就消息的回调,下面有源码 mAsynchronous = async; } public Handler(Looper looper, Callback callback, boolean async) { mLooper = looper; //这里把Handler的mQueue指向Looper的mQueue mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; } private static final boolean FIND_POTENTIAL_LEAKS = false; private static final String TAG = "Handler"; public interface Callback { public boolean handleMessage(Message msg); } public void handleMessage(Message msg) { } public void dispatchMessage(Message msg) { if (msg.callback != null) { //如果接收到消息中,携带这个callback(线程),就执行这里的逻辑 handleCallback(msg); } else { if (mCallback != null) { //如果实例话Handler时,实现回调接口并传入时就会执行实现逻辑 return; } } //如果上述2个条件都不符合,就执行这里了,比如,what=1 //因为这个就是一个空的方法 handleMessage(msg); } }
好了,Handler看了一下,大概明白这个消息机制是怎样的,接下来看看我们通过Handler发送消息的一些方法。
public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); } public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { //延迟多少时间,常用啦 Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); } /**延迟执行,一般我们在进入APP过渡界面,就会用到这个方法,或者是操作耗时任务的时候,耗时时间加上系统时间作为发送时间,*/public final boolean sendMessageDelayed(Message msg, long delayMillis){ if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime (msg, SystemClock.uptimeMillis() + delayMillis); } //设置什么时候发送消息public boolean sendMessageAtTime(Message msg, long uptimeMillis) { //消息队列 MessageQueue queue = mQueue; if (queue == null) {//检查一下消息队列是否有没有传送进来 RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, uptimeMillis); }
还有一些发送的方法我就不一 一列出了,通过上面的观察,可以发现,最后调用了sendMessageAtTime,在此方法内部有直接获取MessageQueue然后调用了enqueueMessage方法;
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this;//把当前Handler的引用也一起传递过去,因为在Looper中通过Hnadler的引用来执行disptchMessage方法 if (mAsynchronous) { msg.setAsynchronous(true); } //发送消息到消息队列 return queue.enqueueMessage(msg, uptimeMillis); } //这个是MessageQueue的方法 boolean enqueueMessage(Message msg, long when) { if (msg.target == null) { throw new IllegalArgumentException ("Message must have a target."); } if (msg.isInUse()) { (msg + " This message is already in use."); } synchronized (this) { if (mQuitting) {IllegalStateException e = new IllegalStateException(msg.target + " sending message to a Handler on a dead thread"); Log.w("MessageQueue", e.getMessage(), e); msg.recycle(); return false; } msg.markInUse(); msg.when = when; Message p = mMessages; boolean needWake; //如果消息队列里面没有消息或者消息执行的时间比里面消息要早,消息队列就会把这条消息设置为第一条消息 //不过一般系统不会有这种情况,因为系统一定有很多消息 if (p == null || when == 0 || when < p.when) { // New head, wake up the event queue if blocked. msg.next = p; mMessages = msg; needWake = mBlocked; } else { // Inserted within the middle of the queue. Usually we don't have to wake // up the event queue unless there is a barrier at the head of the queue // and the message is the earliest asynchronous message in the queue. needWake = mBlocked && p.target == null && msg.isAsynchronous(); Message prev; for (;;) {//如果消息队列有消息(正常情况下,那么该条消息就会被调到最后一条消息) //这个for的作用是为了找到最后一条消息,并放到消息队列的最后 prev = p; p = p.next; if (p == null || when < p.when) { break; } if (needWake && p.isAsynchronous()) { needWake = false; } } msg.next = p; // invariant: p == prev.next prev.next = msg; } // We can assume mPtr != 0 because mQuitting is false. if (needWake) { nativeWake(mPtr); } } return true; }
这些总结是来自Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
1、首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象;因为Looper.prepare()在一个线程中只能调用一次,所以MessageQueue在一个线程中只会存在一个。
2、Looper.loop()会让当前线程进入一个无限循环,不端从MessageQueue的实例中读取消息,然后回调msg.target.dispatchMessage(msg)方法。
3、Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。
4、Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。
5、在构造Handler实例时,我们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法。
这里我从一个handler发送消息---回调消息总结一下。
加上这个图是不是更清晰了,来写下代码,走下流程:
public class MainActivity extends Activity { Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Message message = handler.obtainMessage(); message.what=1; handler.sendMessage(message); }
跟踪源码: handler.sendMessage(message);如下:1、 public final boolean sendMessage(Message msg){ return sendMessageDelayed(msg, 0); }2、 public final boolean sendMessageDelayed( Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime( msg, SystemClock.uptimeMillis() + delayMillis); }3、 public boolean sendMessageAtTime( Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, uptimeMillis); }4、 private boolean enqueueMessage( MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); } 到了这一步,消息已经到了消息队列中了,我们就通过Looper无限循环抽取消息出来,然后通过: //在一个无限循环中不断取出消息 Message msg = queue.next(); msg.target.dispatchMessage(msg);
再通过这个方法,回调到Hanlder中进行消息的处理!
public void dispatchMessage(Message msg) { if (msg.callback != null) { //如果接收到消息中,携带这个callback(线程),就执行这里的逻辑 handleCallback(msg); } else { if (mCallback != null) { //如果实例话Handler时,实现回调接口并传入时就会执行实现逻辑 return; } } //如果上述2个条件都不符合,就执行这里了,比如,what=1 //因为这个就是一个空的方法 handleMessage(msg); } }
大概我个人的理解就是这样了,如果那步不对,请指出,更正我的思路,哈哈,谢谢!
- Android Handler消息处理机制 一些事一些情
- Android中handler消息机制中的一些细节问题
- Android Handler消息处理机制
- Android---Handler消息处理机制
- Android--Handler消息处理机制
- Android消息处理机制Handler
- android处理消息机制----Handler
- Android Handler消息处理机制
- Android 消息处理系统 Handler的一些介绍
- 异步消息机制handler一些理解
- Android应用程序消息处理机制Handler分析
- Android消息处理机制 handler looper messagequene
- android消息处理机制(Looper,Handler,Message)
- 解析Android消息处理机制:Handler…
- Android中的Handler消息处理机制
- Android Handler消息处理机制小记
- Android中的消息处理机制Handler
- Android异步消息处理机制 handler
- 专题7-ARM时钟初始化
- 3D游戏引擎系列十一
- 理解linux time命令的输出
- 指针函数的返回
- Mysql函数INSTR、LOCATE、POSITION VS LIKE
- Android Handler消息处理机制 一些事一些情
- for 续3
- gradle项目中如何支持java与scala混合使用?
- poj 3273 Monthly Expense
- 自定义内容提供者(增删改)
- 索引
- Qt中文显示乱码
- scala 学习笔记(01) 函数定义、分支、循环、异常处理、递归
- 专题8-内存初始化