消息机制--handler

2018-03-09  本文已影响0人  瞬息之李

ThreadLocal: 用来存储不同线程中的数据,在安卓消息机制中,threadloacl用来存储每个线程的looper

looper:消息循环机制,通过Loop.prepare()方法去创建
新建的looper将持有一下几个变量

private static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper;  // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;

新建looper的过程:

public static void prepare(){
    prepare(true);
}

public 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);
    //取得当线线程
    mThread = Thread.currentThread();
}

这里着重介绍ThreadLocal中的get()和set()两个方法如下:
存取原则如下:通过线程来映射对应的value,value中维护了一个数组,数组中存放localThread当前对象及对应的数据,存储规则如下:ThreadLocal的值在table数组中的存储位置总是为ThreadLocal的reference字段所标识的对象的下一个位置

public T get() {
    // Optimized for the fast path.
    Thread currentThread = Thread.currentThread();
    Values values = values(currentThread);
    if (values != null) {
        Object[] table = values.table;
        int index = hash & values.mask;
        if (this.reference == table[index]) {
            return (T) table[index + 1];
        }
    } else {
        values = initializeValues(currentThread);
    }

    return (T) values.getAfterMiss(this);
}

public void set(T value) {
    Thread currentThread = Thread.currentThread();
    Values values = values(currentThread);   
    if (values == null) {
        values = initializeValues(currentThread);
    }
    values.put(this, value);
}

void put(ThreadLocal<?> key, Object value) {  
    cleanUp();  
  
    // Keep track of first tombstone. That's where we want to go back  
    // and add an entry if necessary.  
    int firstTombstone = -1;  
  
    for (int index = key.hash & mask;; index = next(index)) {  
        Object k = table[index];  
  
        if (k == key.reference) {  
            // Replace existing entry.  
            table[index + 1] = value;  
            return;  
        }  
  
        if (k == null) {  
            if (firstTombstone == -1) {  
                // Fill in null slot.  
                table[index] = key.reference;  
                table[index + 1] = value;  
                size++;  
                return;  
            }  
  
            // Go back and replace first tombstone.  
            table[firstTombstone] = key.reference;  
            table[firstTombstone + 1] = value;  
            tombstones--;  
            size++;  
            return;  
        }  
  
        // Remember first tombstone.  
        if (firstTombstone == -1 && k == TOMBSTONE) {  
            firstTombstone = index;  
        }  
    }  
}  


Values values(Thread current) {   
  return current.localValues;
}

handler:
这里先列举下handle的几个构造方法:在新建一个handler对象的时候,其实已经关联了对应线程的looper对象(1.当handle没有动态去设置looper时,根据创建handler的线程,取出looper对象,所以用最终处理消息对应的线程就是创建handler的线程。2.当手动去传对应的looper对象时,最终处理消息的线程是根据looper所在的线程决定的,handle只是looper在执行中的一个对象而已,处理对象是不分线程的),取出了looper的msgqueue

//可以传自定义的looper,callback
  public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

//平时没有传任何参数时,最终会走到这个方法,参数:null,false
//callback:用来在最后处理消息的时候调用,下文给出
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去发送消息的过程:

   public final boolean sendMessage(Message msg)  
   {  
       return sendMessageDelayed(msg, 0);  
   }  
  
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);  
}  
  
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {  
       msg.target = this;  
       if (mAsynchronous) {  
           msg.setAsynchronous(true);  
       }  
       //这里msg被加入消息队列queue  
       return queue.enqueueMessage(msg, uptimeMillis);  

接下来讲解looper如何从msgqueue中取出消息进行处理:
在新建handler对象后,looper要调用loop()方法,不断从msgqueue中取出消息处理,代码如下

public static void loop() {  
     final Looper me = myLooper();  
     if (me == null) {  
         throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");  
     }  
     //从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处理,这个target就是Handler类型  
         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();  
     }  
 }  

从上面loop()方法中,当有msg时,将会执行msg.target.dispatchMessage(msg) 方法,其中msg.target就是handler,这个在sendMseeage时,对msg进行了处理,由此可得最后由handler的dispatchMessage(msg)方法得到执行:

public void dispatchMessage(Message msg) {  
    if (msg.callback != null) {  
        //这个方法很简单,直接调用msg.callback.run();  
        handleCallback(msg);  
    } else {  
        //如果我们设置了callback会由callback来处理消息  
        if (mCallback != null) {  
            if (mCallback.handleMessage(msg)) {  
                return;  
            }  
        }  
        //否则消息就由这里来处理,这是我们最常用的处理方式  
        handleMessage(msg);  
    }  
}  

其中msg.callback是个Runnable接口的实现,什么时候会设置这个callback:handler.post(runnable),post方法最终会被封装成msg对象传过去

public final boolean post(Runnable run){
  return sendMessageDelay(getPostMessage(run),0);
}

mCallback :这个是在新建handler对象的时候传进去的,当没有传时为null
最后才会执行handler的handleMessage(msg)方法

注意事项:

  1. 在主线程创建handle时,系统默认提供了mainLooper,所以不需要再自己去创建looper了。但是在子线程时,需要自己去创建looper,并要去手动执行loop()方法去轮询查找消息,
  2. msg在哪个线程执行是依赖handler创建时的线程?还是looper所在的线程?--- 答案是looper所在的线程,因为在处理消息时,最终是由looper的loop()方法调用,再去调用handler对应的handleMessage()方法。
    这里注意一点,对象是不分线程的

这里举几个典型的例子:

子线程想要在主线程中执行一段代码
new Handler(getMainLooper()).post(new Runnable() {

        @Override

        public void run() {

            //todo

        }

    })
上一篇下一篇

猜你喜欢

热点阅读