Android源码阅读之——Handler(一)

一直以来,都对Handler不甚了解,如今花点时间自己去阅读源码,看看Handler是怎样运用的。
在系统自带的Launcher2中,就有使用Handler的,下面就看看Handler在其中的运用。

任务的前半生

Launcher.java (位于packages\apps\launcher2\scr\com\android\launcher2下)onCreate() 方法中,会调用LauncherModel.javastartLoader() 方法,其中调用了Handlerpost(Runnable r) 方法。

//LauncherModel.java

public void startLoader(boolean isLaunching, int synchronousBindPage) {
     //此处略去一部分代码

    sWorkerThread.setPriority(Thread.NORM_PRIORITY);

    //sWorker 是类LauncherModel的一个类成员变量,Handler的一个实例,
    //mLoaderTask是实现Runnable接口的类LoaderTask的一个实例
    sWorker.post(mLoaderTask);
    //此处略去一部分代码
}

我们追踪一下mLoaderTask的去向。post(Runnable r)mLoaderTask 传给了getPostMessage(r) ,而后者返回了一个Message 对象,mLoaderTask 封装其中。

//Handler.java

    public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
//Handler.java

    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        //mLoaderTasker 赋给了Message的callback成员变量
        m.callback = r;
        return m;
    }

接着,封装着mLoaderTaskMessage 继续被传送,经过sendMessageAtTime() 传入到enqueueMessage() 中,通过跟踪Handler的函数调用我们发现,实际上,Handlerpost*() 方法,辗转都会调用到enqueueMessage() 方法。

//Handler.java

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

    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 queue = mQueue; ,出现了mQueueHandler 的一个实例变量,这个mQueue 哪来的我们稍后讨论,在这里把封装mLoaderTaskMessageMessageQueue 一同传给了enqueueMessage()

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

我们看到Handler 把自己也封装给了Messagetarget 函数并传给了MessageQueue ,为什么要把自己封装进去呢?我们先带着疑问接着往下看。到这里,我们终于知道,我们 postmLoaderTask 被保存在了MessageQueue 维持的一个队列里。貌似Handler 的任务已经完成,mLoaderTask 已经出了服务区,但是它又是怎么被执行的呢?就像快递经过多个转运中心已经到目的地了,接下来谁把他取走呢?

任务的下半辈子

这貌似无从下口啊,咋知道谁把它拿走了?细细推敲,我们发现现在既然把它交给了MessageQueue 的实例mQueue ,我们只能先看看mQueue 哪来的了。
Handler.java 中,对mQueue 的赋值只有两处地方,分别是Handler 的两个构造函数中,说明mQueue 是在 Handler 实例化的时候赋值的。那我们去看看在哪里创建了Handler 的对象。
通过上面我们知道,我们最初调用post() 是在LauncherModel.java 中,调用的对象是sWorker ,而sWorker 的的赋值语句如下:

//LauncherModel.java

  private static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");
    static {
        sWorkerThread.start();
    }
    private static final Handler sWorker = new Handler(sWorkerThread.getLooper());

可以看到,sWorkerThreadsWorker 都是类变量,也就是说类LauncherModel创建实例的时候,就会创建一个HandlerThread 实例并运行,并且创建了一个Handler 实例。
上面说说到,mQueue 有两处赋值的地方,分别是Handler 的两个构造函数,而Handler 的所有构造函数,最终都会调用到这两个构造函数其中之一。而我们源码中最终调用到的,是下面这个,

    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

这样,我们就弄清楚了,Handler 中的 mQueueLooper 维持的。这个Looper ,是通过HandlerThreadgetLooper() 获得。我们来看看 getLooper() 内部的代码,

//HandlerThread.java

public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }

        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

最后返回的是sWorkerThread 的一个成员函数mLooper ,我们跳转到它定义的地方,Looper mLooper; 看到确实是Looper 的一个引用。接下啦看看它在什么地方赋值,

//HandlerThread.java

    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
        //此处赋值
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

整个HandlerThread 中只有此处对mLooper赋值。接下来我们继续进入myLooper 看看到底其中做了什么。

//Looper.java

public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}

接下来我们接着看看sThreadLocal 定义的地方,

//

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

发现它是Looper 的一个类变量,还有疑问啊,Looper 变量啥时候放进去的呢?浏览Looper.java 发现只有调用 sThreadLocal.set() 的地方只有一处,就是在prepare() 中。

//Looper.java

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

这回我们也知道了,为什么要先调用prepare() ,因为只有调用此函数后,才会创建Looper 的实例;到这里我们知道了,在调用prepare() 之后,整个类中就有持有了线程中一个唯一的Looper 实例,之后,通过Looper.myLooper() 获得的Looper 的实例是同一个。因此sWorkerThreadsWorker 就持有的是同一个Looper 实例。
回到上面的run() 函数,接着会执行loop() 函数。

//Looper.java

public static void loop() {
        final Looper me = myLooper();
        //.......
        final MessageQueue queue = me.mQueue;
        //.......
        for (;;) {
            Message msg = queue.next(); // might block
        //.......
            // This must be in a local variable, in case a UI event sets the logger
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }
            //.......
            try {
                msg.target.dispatchMessage(msg);
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            //......
            msg.recycleUnchecked();
        }
    }

我们发现,在这函数中循环执行到msg.target.dispatchMessage(msg);target ,上面我们发现Handler 的对象在把Message 传给 MessageQueue 的时候把自己封装进了Message ,因此兜了一圈,Message 在队列中呆了一会儿后,又被传回了Handler 里面。

//Handler.java

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

最终调用到handleCallback(); 最终,我们封装的Runnablerun() 函数就在这执行了。至此,我们post()Runnable 走完了全程。

//Handler,java

   private static void handleCallback(Message message) {
        message.callback.run();
    }

简单总结任务的一生?

简单捋一捋,我们想要的执行的Runnable ,先由Handler 层层递送到 了Looper 维护的 MessageQueue ,然后,Looper 又把它取出来交给了Handler 去执行。
我们不禁黑人问号,这样兜了一圈图个啥?
其实这样一圈下来,Runnable已经从一个线程,传递到了另一个线程。因为原本Handler 是在创建它的线程中,经过传递,通过Message ,他进入到了持有Looper 的 “launcher-loader”线程中,因此他就在另一个线程中执行了。
这里,为了直观感受Runnable 确实传递到了另一个线程,我们来写个demo。

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        HandlerThread hand = new HandlerThread("demo thread"){
            public void run(){
                Log.e("can reach?","yes");
                super.run();

            }
        };
        hand.start();
        Handler handler = new Handler(hand.getLooper());
        handler.post(new Runnable() {
            @Override
            public void run() {
                Log.e("Who invoke me:",Thread.currentThread().getName());
            }
        });
        //Log.e("",Thread.currentThread().getName());

    }

上面,我们创建了一个名叫“demo thread”的线程,并在主线程中发送了一个Runnable 对象。通过输出日志,我们发现执行的时候确实是在另一个线程中的。我们的结论是对的!
这里写图片描述
这里,我们仍有一些疑问,有时候我们直接在主线程中创建一个Handler 实例,然而并没有调用Looper.prepare() ,为什么它不挂掉?
这个,就留着下次再分析吧。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值