继续创造,加速生长!这是我参加「日新方案 10 月更文应战」的第1天,点击查看活动详情,希望咱们多多支撑,帮忙点个赞,谢谢!

前语

感觉时刻真的过的飞快,转瞬我都作业大半年了,仿佛学生时代的我就在昨日,而今日却要为生计而奔走。记住小时候很爱看书,那时候最想买书店那种上面写着名著,包装又很漂亮的,而且读完书还能和小伙伴们共享自己获得的新知,而现在都化为乌有,只留下为着不知怎样的未来之景而不得不看源码的我。

每次阅览源码,我都想着许多过往云烟,能够说,全部不在一样,不过,想再多又如何,倒不如按下心思,在手中记下这全部更为妥当。仍是看看这些充满智慧结晶的源码吧!

正篇

本想着先深入一下post办法的,但转念仍是墨守成规吧,让咱们接着往下看:

/**
 * Runs the specified task synchronously.
 * <p>
 * If the current thread is the same as the handler thread, then the runnable
 * runs immediately without being enqueued.  Otherwise, posts the runnable
 * to the handler and waits for it to complete before returning.
 * </p><p>
 * This method is dangerous!  Improper use can result in deadlocks.
 * Never call this method while any locks are held or use it in a
 * possibly re-entrant manner.
 * </p><p>
 * This method is occasionally useful in situations where a background thread
 * must synchronously await completion of a task that must run on the
 * handler's thread.  However, this problem is often a symptom of bad design.
 * Consider improving the design (if possible) before resorting to this method.
 * </p><p>
 * One example of where you might want to use this method is when you just
 * set up a Handler thread and need to perform some initialization steps on
 * it before continuing execution.
 * </p><p>
 * If timeout occurs then this method returns <code>false</code> but the runnable
 * will remain posted on the handler and may already be in progress or
 * complete at a later time.
 * </p><p>
 * When using this method, be sure to use {@link Looper#quitSafely} when
 * quitting the looper.  Otherwise {@link #runWithScissors} may hang indefinitely.
 * (TODO: We should fix this by making MessageQueue aware of blocking runnables.)
 * </p>
 *
 * @param r The Runnable that will be executed synchronously.
 * @param timeout The timeout in milliseconds, or 0 to wait indefinitely.
 *
 * @return Returns true if the Runnable was successfully executed.
 *         Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 *
 * @hide This method is prone to abuse and should probably not be in the API.
 * If we ever do make it part of the API, we might want to rename it to something
 * less funny like runUnsafe().
 */
public final boolean runWithScissors(@NonNull Runnable r, long timeout) {
    if (r == null) {
        throw new IllegalArgumentException("runnable must not be null");
    }
    if (timeout < 0) {
        throw new IllegalArgumentException("timeout must be non-negative");
    }
    if (Looper.myLooper() == mLooper) {
        r.run();
        return true;
    }
    BlockingRunnable br = new BlockingRunnable(r);
    return br.postAndWait(this, timeout);
}

好家伙,这个注释都快看晕了,一眼下去连代码都没找到,而且又是一个没触摸过的办法, 办法名:runWithScissors(),老规矩,先解释一下注释,其实注释也挺风趣的!

首要办法名头上顶了一个@hide的注解,表明这个办法不希望一般开发者运用,然后还玩笑道:”此办法容易被滥用,或许不应该出现在 API 中。假如咱们真的让它成为 API 的一部分,咱们或许得把它重命名为像 runUnsafe() 这样不那么风趣的东西比较好。”这段话形象的告知了咱们这个办法应该成为一个冷门办法,但经过我查询资料和源码发现,这个办法用到的地方其实不少,在 Framework 中,更是很多场景都用到了,一些博客也举例了,例如比较了解的 WMS 发动流程中,分别在main()initPolicy()中,经过runWithScissors()切换到 “android.display” 和 “android.ui” 线程去做一些初始作业:

private void initPolicy() {
  UiThread.getHandler().runWithScissors(new Runnable() {
    public void run() {
      // 运转在"android.ui"线程
      WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());
      mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this);
    }
  }, 0);
}

大局查找也能看到众多运用场景:

从源码与官方文档看之Handler篇(十)

之所以在Framework中有这么多运用场景而不建议咱们用是由于该办法存在危险,这点在注释第二段重点阐明:这种办法很危险!运用不当会导致死锁。切勿在持有任何锁时调用此办法,或以或许可重入的办法运用它。这段话表明该办法有死锁危险以及超时后,没有撤销的逻辑(即经过 runWithScissors() 发送 Runnable 时可设置超时时刻,但当超时唤醒时,会直接 false 退出。所以当超时退出时,这个 Runnable 仍然还会在方针线程的 MessageQueue 中,并没有被移除去,这也就导致它最终仍是会被 Handler 线程调度并履行。)

接着咱们再去看看它的作用:runWithScissors() 承受一个 Runnable,并且能够设置超时时刻,先简单的对入参进行校验;假如当前线程和 Handler 的处理线程一致,则直接运转 run() 办法;线程不一致,则经过 BlockingRunnable 包装一下,并履行其 postAndWait() 办法,也就是说咱们能够经过堵塞的办法,向方针线程发送使命,并等候使命履行结束。

而注释又阐明:在后台线程必须同步等候必须在处理程序线程上运转的使命完结的情况下,此办法有时很有用。但是,这个问题通常是糟糕规划的预兆。在采用这种办法之前,请考虑改进规划(假如或许),哈哈哈,结果仍是不希望咱们直接运用该办法,假如想运用,能够考虑咱们自己重新完成一个 BlockingRunnable 去运用。而且得注意安全运用runWithScissors()还需要满足 2 个条件:

  1. Handler 的 Looper 不允许退出,比如说, Android 主线程 Looper 就不允许退出;
  2. Looper 退出时,要运用安全退出即quitSafely()办法退出;

总结

总归,这个注释专长的办法不推荐运用,仅为咱们阅览源码所需要,毕竟办法存在缺陷,在阅览源码又或许会遇到,所以仍是得看看的,而且这个办法还涉及Synchronized 锁和它的等候/通知机制,能够温习或学习一些临界问题,线程的同步、死锁,以及 Handler 的退出办法对音讯的影响这方面的知识集。

所以,后续我也要温习一下有关这些锁啊,同步啊之类的知识了。

路漫漫兮其修远兮,吾将上下而求索