handler源码分析

提到handler,我们总会很直接的说:Activity中做操作,handler然后把消息(Message)发到消息队列(MessageQueue)中,里面有个轮询器(Looper),取出消息后处理。

那么:

1、哪儿来的Looper?
2、Looper在哪儿(主线程还是子线程)?
3、ThreadLocal在哪儿(主线程还是子线程)?
4、Looper的loop方法又是在哪儿调用的呢?
5、MessageQueue在哪儿(主线程还是子线程)?
6、Handler在哪儿(主线程还是子线程)?

7、在哪儿发的消息?
8、消息发到哪儿去了?
9、消息最后怎么被处理的?

10、怎么就把子线程发的消息变换到了主线程?

正式开始之前,先看一个handler使用的案例:

private static class MyHandler extends Handler {
        private final WeakReference<MainActivity> mActivity;

        private MyHandler(MainActivity activity) {
            mActivity = new WeakReference<MainActivity>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            MainActivity activity = mActivity.get();
            if (activity != null) {
                switch (msg.what) {
                    case 0:
                        Log.e("chen", "handler");
                        break;
                    default:
                        break;
                }
            }
        }
    }

    private final MyHandler mHandler = new MyHandler(this);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mHandler.sendEmptyMessageDelayed(0, 10000);

    }

启动一个Activity,10秒以后打印一句话。
关于这个写法,可能有的人不理解,之前不都是

 private Handler mHandler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
                case 0:

                    break;
                default:
                    break;
            }
        }
    };

这样用么?
我这里做一下说明:Handler 属于 TLS(Thread Local Storage) 变量, 生命周期和 Activity 是不一致的。万一 Handler 发送的 Message 尚未被处理,则该 Message 及发送它的 Handler 对象将被线程 MessageQueue 一直持有。因此这种实现方式一般很难保证跟 View 或者 Activity 的生命周期保持一致,故很容易导致Activity销毁的时候无法正确释放,可能会造成内存泄露,所以用了弱引用。

最后结束的时候,要记得移除:

@Override
    protected void onDestroy() {
        if (handler != null && handler.hasMessages(0)) {
            handler.removeMessages(0);
        }
        super.onDestroy();
    }

对应源码:

  /**
     * Remove any pending posts of messages with code 'what' that are in the
     * message queue.
     */
    public final void removeMessages(int what) {
        mQueue.removeMessages(this, what, null);
    }

好了,正式开始源码解读:
这里,我要剧透一下,我们需要找到:ActivityThread
我们都知道,要想用handler,就需要先有Looper(子线程没有,需要手动创建)。可是我们在实际使用的时候(在主线程中直接使用),是没有创建的,那么,就只有一个解释,我们创建的Activity的父类,肯定有创建方法。最后,在Activity(Activity的源码,不是我们自己创建的MyActivity这种类型的)中,有个方法:

    final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window, ActivityConfigCallback activityConfigCallback) {
        attachBaseContext(context);
        ......
        mMainThread = aThread;
        ......
    }

这里,终于出现了ActivityThread。

这个attach方法,上面没有源码注释说明,我在Activity的API中也没有看到,但是Fragment的生命周期中有,参考Fragment的

/**
* Called when a fragment is first attached to its context.
* {@link #onCreate(Bundle)} will be called after this.
*/
@CallSuper
public void onAttach(Context context) {
......
}

可以这么理解,Activity依附在window上以后,这个attach方法就被调用了。

然后,我们进去看ActivityThread源码,在它的main方法中:
(不同版本的API对应的源码,会有点区别,但是关键地方一样,不用纠结这个,这里的ActivityThread,是API 26的)

 public static void main(String[] args) {
        ......
        Looper.prepareMainLooper();
        ......
        Looper.loop();
        ......

    }

只看我们关心的代码。
其中:
首先看一下prepareMainLooper

/**
* Initialize初始化 the current现在的,当前的 thread as a looper, marking标记 it as an
* application's main looper. The main looper for your application
* is created by the Android environment环境, so you should never need
* to call this function yourself.  See also: {@link #prepare()}
*/
public static void prepareMainLooper() {
    prepare(false);
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        sMainLooper = myLooper();
    }
}

其中,prepare(false)中的代码是:

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

在Looper中:

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

而 new Looer(boolean b)方法下的源码是:

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

到此为止,通过源码,上面提出的10个问题中,可以回答前5个:
1、哪儿来的Looper?
它是主线程中ActivityTread中main方法下通过Looper.preperMainLooper()创建的。即:ActivityTread创建的时候创建的
2、Looper在哪儿(主线程还是子线程)?
Looper在主线程中创建,因此Looper在主线程中
3、ThreadLocal在哪儿(主线程还是子线程)?
在Looper中,用来存取Looper,因此也在主线程中。每一个线程可以直接把数据存取到ThreadLocal中,而数据是隔离的互不干扰,用作线程的数据隔离。
4、Looper的loop方法又是在哪儿调用的呢?
在ActivityThread的main方法中我们看到了,Looper.loop();,所以,调用位置,就是在ActivityThread创建的时候
5、MessageQueue在哪儿(主线程还是子线程)?
在looper创建的时候,MessageQueue也被new了,所以,MessageQueue也在主线程中

接下来,继续看后面的问题:
6、Handler在哪儿(主线程还是子线程)?
我们在创建一个Activity以后,会直接声明、定义handler,那是主线程,所以,handler是在主线程的。当然了,如果你开了个子线程,在子线程中创建了handler,它就在子线程。

7、在哪儿发的消息?
这个问题没什么技术含量,就是放消息,然后send,不过也提一下。在你想要发消息的时候:

Message message = Message.obtain();
message.what = 1;
handler.sendMessage(message);

接下来的问题,就需要继续看源码了:
handler的所有sendXXX方法,最后都会调用到:sendMessageAtTime(Message msg, long uptimeMillis)

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    MessageQueue queue = mQueue;
    if (queue == null) {
        RuntimeException e = new RuntimeException(
            this + " sendMessageAtTime() called with no mQueue");
        og.w("Looper", e.getMessage(), e);
        return false;
    }
    return enqueueMessage(queue, msg, uptimeMillis);
}

在return那里,有个方法,从字面意思,就是“消息入队”

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

queue.enqueueMessage这里开始往后,就开始进入消息队列(MessageQueue)了
源码:

boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(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(TAG, 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 (;;) {
                    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;
    }

这里,可以回答第8个问题:
8、消息发到哪儿去了?
通过handler.sendXXX发出来的消息,最后都会汇总到Handler中的sendMessageAtTime,然后在Handler中的enqueueMessage方法中,交给MessageQueue中的enqueueMessage方法,完成消息入队。

现在,我们回到ActivityThread的main方法中,看Looper.loop();这句。
Looper中:(这里是消息分发、处理的核心。版本号差距较大的话,这里的源码可能会有一点不一样,但是核心处理都一样,这里,我只展示需要着重分析的部分)

    /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    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;
        ......
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
            ......
            try {
                msg.target.dispatchMessage(msg);
                ......
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            ......
        }
    }

这里其实就是做了2件事:取出消息(如果有的话),分发出去。

在回答问题前,我先说2个事:
1、Looper的退出情况。什么时候,Looper会退出(被清理掉呢)?回到ActivityThread,在ActivityThread下的handleMessage中,可以看到

public void handleMessage(Message msg) {
    switch (msg.what) {  
        ......
        case EXIT_APPLICATION:
            if (mInitialApplication != null) {
                mInitialApplication.onTerminate();
            }
            Looper.myLooper().quit();
            break;
        ......
    }           
    ......        
}

2、Looper.loop()用的是一个for循环,是一个死循环。为什么没有阻塞程序?
因为Android 的是由事件驱动的,looper.loop() 不断地接收事件、处理事件,每一个点击触摸或者说Activity的生命周期都是运行在 Looper.loop() 的控制之下,如果它停止了,应用也就停止了。只能是某一个消息或者说对消息的处理阻塞了 Looper.loop(),而不是 Looper.loop() 阻塞它。也就说我们的代码其实就是在这个循环里面去执行的,当然不会阻塞了。这么说有证据吗?有,就在ActivityThread中的handleMessage,那里接受处理了Activity的各种情况也包括Activity的生命周期状态。如:

public void handleMessage(Message msg) {
    switch (msg.what) {  
       case LAUNCH_ACTIVITY: {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
            ......
        } break;
        case RELAUNCH_ACTIVITY: {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
            ......
        } break;
        ......
        ......
    }                         
}

好了,现在回到loop()中的源码中,看这句

msg.target.dispatchMessage(msg);

这句就是消息的分发了。
msg.target是什么呢?在Message中:

 Handler target;
 public void setTarget(Handler target) {
     this.target = target;
 }

由此可知,msg.target,就是handler,在Handler中:

    /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
/**
* Subclasses must implement执行、实现 this to receive messages.
*/
public void handleMessage(Message msg) {
}

看到了handleMessage,是不是很亲切。终于完了。。。

现在,回到第9个问题:
9、消息最后怎么被处理的?
消息在Looper.loop()中通过轮询方式拿出来,然后交给handler中的dispatchMessage处理,最后,在交给handleMessage,让我们自行处理

10、怎么就把子线程发的消息变换到了主线程?
问题6中已经说了,handler是在主线程中的,在子线程中,调用主线程的handler把消息发到消息队列,最后,消息被发到了主线程中的handleMessage中

到此,上面10个问题已经回答完了。关于handler,基本没什么问题了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值