Android中关于Handler Looper理解

在Android中每个应用的UI线程是被保护的,不能在UI线程中进行耗时的操作,其他的子线程也不能直接进行UI操作。

为了达到这个目的Android设计了handler Looper这个系统框架。

首先讲解在主线程中使用Handler时源码跟踪过程。

正常在activity的oncreate函数中定义个handler,这种情况下就是默认的主线程的handler,并去复写该类的handleMessage()函数。

private final Handler mMessageHandler = new Handler(){
    @Override
    public void handleMessage(Message msg){
        ....;
    }
}

 在这里new 了一个Handler类,跟入系统代码

106    /**
107     * Default constructor associates this handler with the {@link Looper} for the
108     * current thread.
109     *
110     * If this thread does not have a looper, this handler won't be able to receive messages
111     * so an exception is thrown.
112     */
113    public Handler() {
114        this(null, false);
115    }
188    public Handler(Callback callback, boolean async) {
189        if (FIND_POTENTIAL_LEAKS) {
190            final Class<? extends Handler> klass = getClass();
191            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
192                    (klass.getModifiers() & Modifier.STATIC) == 0) {
193                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
194                    klass.getCanonicalName());
195            }
196        }
197
198        mLooper = Looper.myLooper();
199        if (mLooper == null) {
200            throw new RuntimeException(
201                "Can't create handler inside thread that has not called Looper.prepare()");
202        }
203        mQueue = mLooper.mQueue;
204        mCallback = callback;
205        mAsynchronous = async;
206    }

最后需要对mQueue;mCallback;mAsynchronous这三个变量赋值。
这里注意 mLooper = Looper.myLooper(); 对mLooper的初始化。这里进入了Looper类

191    public static @Nullable Looper myLooper() {
192        return sThreadLocal.get();
193    }
68    // sThreadLocal.get() will return null unless you've called prepare().
69    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
92    private static void prepare(boolean quitAllowed) {
93        if (sThreadLocal.get() != null) {
94            throw new RuntimeException("Only one Looper may be created per thread");
95        }
96        sThreadLocal.set(new Looper(quitAllowed));
97    }
98

最后new Looper(quitAllowed) 在这里在当前thread中新建了一个Looper对象(所以从这里可以看出来Looper是属于当前thread的)。
正常在我们自己new的线程中都需要调用Looper.prepare();语句来为当前线程new一个looper对象。但是对于UI线程中创建的looper是不需要的,因为在初始化UI线程时就已经写好了。

正常UI线程初始化时调用prepareMainLooper这个函数。

99    /**
100     * Initialize the current thread as a looper, marking it as an
101     * application's main looper. The main looper for your application
102     * is created by the Android environment, so you should never need
103     * to call this function yourself.  See also: {@link #prepare()}
104     */
105    public static void prepareMainLooper() {
106        prepare(false);
107        synchronized (Looper.class) {
108            if (sMainLooper != null) {
109                throw new IllegalStateException("The main Looper has already been prepared.");
110            }
111            sMainLooper = myLooper();
112        }
113    }

对于一般的子线程需要继续调用Looper.loop来启动loop循环进行消息发送。
而同样对于UI线程的looper同样是在初始化过程中已经调用好了。

128    public static void loop() {
129        final Looper me = myLooper();
130        if (me == null) {
131            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
132        }
133        final MessageQueue queue = me.mQueue;
..............
142        for (;;) {
143            Message msg = queue.next(); // might block
144            if (msg == null) {
145                // No message indicates that the message queue is quitting.
146                return;
147            }
。。。。。。。。。。
158            msg.target.dispatchMessage(msg);

在这个loop()函数中就能真正看到消息循环机制。在一个死循环中for(;;)不断从queue消息队列中获取messager,如果没有将阻止在该端口等待下一个messager。
在获取一个消息后则放入message中的targe中进行消息分发。

这里的target其实就是最开始在封装一个message进行发送时传入的handler,所以从这里也可以看出,最后消息还是通过handler传入到它所在的线程中调用handleMessage()进行处理。

message.java 的成员变量:

public final class Message implements Parcelable {
   public int what;
   public int arg1;
   public int arg2;
   public Object obj;
   public Messenger replyTo;
   public int sendingUid = -1;
   /*package*/ static final int FLAG_IN_USE = 1 << 0;
   /** If set message is asynchronous */
   /*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;
   /** Flags to clear in the copyFrom method */
   /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;
   /*package*/ int flags;
   /*package*/ long when;
   /*package*/ Bundle data;
   /*package*/ Handler target
   /*package*/ Runnable callback;
   // sometimes we store linked lists of these things
   /*package*/ Message next;

在主线程中创建handler:

如上所述,如果在主线程中创建handler,并不需要经历初始化looper等操作,因为在主线程刚创建的时候系统就自动为该主线程创建好了并启动了循环,所以我们只需要在主线程中new一个handler并且重写handleMessage方法,当其他的子线程需要更新UI的时候,只需要获取该handle对象,并将信息发送即可。

 

在自己创建的子线程中创建handler:

当在自己创建的子线程中创建handler时,需要自己手动创建looper,初始化并启动循环。

具体步骤:

1)初始化looper: Looper.prepare();

2)  创建looper对象: mLooper = Looper.myLooper();

3) 启动looper循环: Looper.loop();

这样就将子线程中的looper启动起来,接下来就只要定义我们自己需要的handler并重写handleMessage方法即可。

 

在Android中还提供一种常用的handler就是HandlerThread

创建步骤:

1)新建一个HandlerThread实例: mListenerThread = new HandlerThread("XXXX");

2) 启动该handler实例:  mListenerThread.start();

3) 将该looper开启循环: final Looper looper = mListenerThread.getLooper()

4)  定义该handler的handleMessage方法

HandlerThread uIhandlerThread = new HandlerThread("update");
uIhandlerThread.start();
finale Looper looper = uIhanderThread.getLooper();
if(looper != null){
   Handler uIhandler = new Handler(looper) {
       @Override
        public boolean handleMessage(Message msg) {
          ...
         return true;  
        }
    };
}

 

posted on 2017-04-01 20:30  kma  阅读(3125)  评论(0编辑  收藏  举报

导航