zoukankan      html  css  js  c++  java
  • android的handler、looper、Message之间的关系

    handler:绑定到一个线程上,一个线程可以有多个handler

    looper:线程跟looper是一一对应的,所以looper不能被调用两次否则会抛出异常

    messge:handler利用message来携带消息

    messagQueue:用来状态message,一个looper对应一个消息队列

    如何来判断一个消息队列对应一个handler呢,在sendmessage中获取到一个消息队列的持有者looper

    looper的两个方法:prepare()和loop()

    1.

    public static final void prepare() {
            if (sThreadLocal.get() != null) {
                throw new RuntimeException("Only one Looper may be created per thread");
            }
            sThreadLocal.set(new Looper(true));
    }

    给当前线程一个设定一个looper实例

    2.

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

    给这个looper创建一个消息队列(在构造函数中),并返回当前的线程

    3.

    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;
                }
    
                // 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);
                }
    
                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);
                }
    
                msg.recycle();
            }
    }
     public static Looper myLooper() {
            return sThreadLocal.get();
        }

    直接拿到该looper实例中的消息队列,然后循环每一个message(进入了无限循环),遍历消息之后会通过这个message的handler进行分发。

    msg.target.dispatchMessage(msg); 中的target是handler

    总结looper的主要作用

    1) 与当前线程绑定,保证一个线程只会有一个Looper实例,同时一个Looper实例也只有一个MessageQueue。
    2) loop()方法,不断从MessageQueue中去取消息,交给消息的target属性的dispatchMessage去处理。

    handler

    public Handler() {
            this(null, false);
    }
    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());
                }
            }
    
            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;
        }

    handler绑定到looper上,由于一个looper对一个一个消息队列,这样这个handler就绑定到这个looper上了,也同时绑定到了这个线程上。

    handler.sendMessgae()是用来讲Message添加进消息队列的。。dispatchmessage才是用于分发的(如上looper介绍)

    public void dispatchMessage(Message msg) {
            if (msg.callback != null) {
                handleCallback(msg);
            } else {
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                handleMessage(msg);
            }
        }
     public void handleMessage(Message msg) {
        }
        

    handleMessage此时是空的函数,需要我们之后的复写

    步骤:

    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)最终调用的方法。
    
    6、handler也可以进行存在于子线程中,为什么我们一般见到的都在主线程中呢?因为一般是针对UI空间更新的操作是不安全的所以handler放在主线程中,如果不存在这样的业务,当然可以用handler

       

  • 相关阅读:
    idea 缺失右侧maven窗口
    SpringCloud
    Java面试题——Java基础
    json对象、json字符串的区别和相互转换
    java中的 private Logger log=Logger.getLogger(this.getClass());
    http网络编程
    ansible和helm
    template模板
    http中get和post请求方式
    session和cookie
  • 原文地址:https://www.cnblogs.com/zhengtu2015/p/4914270.html
Copyright © 2011-2022 走看看