当前位置: 移动技术网 > IT编程>移动开发>Android > Android中检测当前是否为主线程最可靠的解决方法

Android中检测当前是否为主线程最可靠的解决方法

2019年07月24日  | 移动技术网IT编程  | 我要评论

淘男网推广,每天每夜110404中字,同人漫画h

如果在android中判断某个线程是否是主线程?对于这个问题,你可能说根据线程的名字,当然这个可以解决问题,但是这样是最可靠的么?万一某天google一下子将线程的名字改称其他神马东西呢。

方法揭晓

下面的方法是最可靠的解决方案。

复制代码 代码如下:

public static boolean isinmainthread() {
      return looper.mylooper() == looper.getmainlooper();
}

实际上,写到这里就基本解决了文章标题的问题了,但是仅仅研究到这里太肤浅了,刨的不够深,所以需要继续,希望你也可以继续读下去。

刨根问底

实验一

好,现在,我们对这个稳定的方法做一些测试,首先,下面的方法会增加一些调试打印信息。

复制代码 代码如下:

private boolean isinmainthread() {
    looper mylooper = looper.mylooper();
  looper mainlooper = looper.getmainlooper();
  log.i(logtag, "isinmainthread mylooper=" + mylooper
      + ";mainlooper=" + mainlooper);
  return mylooper == mainlooper;
}

好,然后我们在主线程中运行一个测试,调用上述方法。比如我们这样调用。

复制代码 代码如下:

log.i(logtag, "testinmainthread inmainthread=" + isinmainthread());

ok,我们看一下输出日志。验证ok。

复制代码 代码如下:

i/testinmainthread(32028): isinmainthread mylooper=looper{40d35ef8};mainlooper=looper{40d35ef8}
i/testinmainthread(32028): testinmainthread inmainthread=true

实验二

现在我们继续在一个没有消息循环的非主线程,进行验证。

复制代码 代码如下:

new thread() {
    @override
    public void run() {
      log.i(logtag, "testin not in mainthread ismainthread="
          + isinmainthread());
      super.run();
  }
}.start();

正如我们看到的如下日志结果,主线程的looper(翻译成循环泵,不是很好听)已经被初始化赋值。但是我们新创建的线程的looper还是null。这是因为android中的线程默认没有一个和它绑定了的消息循环(threads by default do not have a message loop associated with them. of course, the method works)

复制代码 代码如下:

i/testinmainthread(32028): isinmainthread mylooper=null;mainlooper=looper{40d35ef8}
i/testinmainthread(32028): testin not in mainthread ismainthread=false

实验三

继续,我们创建一个绑定了消息循环的线程,根据android开发者文档说明,以下是一个典型的创建消息循环线程的示例,使用单独prepare()方法和loop()方法来创建一个绑定到looper的handler。

复制代码 代码如下:

new thread() {
  private handler mhandler;
  @override
  public void run() {
      looper.prepare();
      mhandler = new handler() {
            public void handlemessage(message msg) {
              // process incoming messages here
          }
      };
      log.i(logtag, "testinnonmainlooperthread ismainthread="
            + isinmainthread());
      looper.loop();
  }
     
}.start();

ok,现在再次检查以下日志,

复制代码 代码如下:

i/testinmainthread(32028): isinmainthread mylooper=looper{40d72c58};mainlooper=looper{40d35ef8}
i/testinmainthread(32028): testinnonmainlooperthread ismainthread=false

两个looper都被初始化赋值了,但是他们是不同的对象。

原理发掘

但是,这是为什么呢,这里面有什么奥秘呢? 好,让我们看以下looper.class

复制代码 代码如下:

// sthreadlocal.get() will return null unless you've called prepare().
static final threadlocal<looper> sthreadlocal = new threadlocal<looper>();
private static looper smainlooper;  // guarded by looper.class

/**
 * 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();
    }
}

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

/**
 * return the looper object associated with the current thread. 
 * returns null if the calling thread is not associated with a looper.
 */
public static looper mylooper() {
    return sthreadlocal.get();
}

 /** returns the application's main looper, which lives in the main thread of the application.
 */
public static looper getmainlooper() {
    synchronized (looper.class) {
        return smainlooper;
    }
}

对于主线程来说,preparemainlooper这个方法会被android运行环境调用,而不是程序显式调用。通过这个方法,主线程的looper被创建,并且将对象引用传递给smainlooper。所以保证了主线程mylooper()获取到的引用和getmainlooper()获取到的都是同一个引用。

对于没有消息循环的非主线程,默认的当前线程的looper是null,因为你从来没有手动地调用prepare(),所以它和主线程的looper不一样。

对于绑定了消息循环的非主线程,当调用looper.prepare方法时,主线程的looper已经由android运行环境创建,当调用prepare方法后,绑定到这个非主线程的looper被创建,当然,这不可能和主线程的looper一样。

综上所述,这个方法是可靠的。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网