Android Handler消息处理机制 一些事一些情

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);如下:

1public final boolean sendMessage(Message msg){
        return sendMessageDelayed(msg, 0);
  }

2public final boolean sendMessageDelayed(
    Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(
        msg, SystemClock.uptimeMillis() + delayMillis);
    }

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

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

大概我个人的理解就是这样了,如果那步不对,请指出,更正我的思路,哈哈,谢谢!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值