如何检查当前线程不是主线程?

462

我需要检查运行特定代码的线程是否为主线程(UI线程)。如何实现?


演示如何使用线程示例来查找代码运行在哪个线程上。http://code2concept.blogspot.in/2015/02/androidhow-to-find-on-which-thread-code.html - Nitesh Tiwari
15个回答

815
Looper.myLooper() == Looper.getMainLooper()

如果这个返回值为true,那么你就在UI线程上了!


142

您可以使用以下代码来判断当前线程是否为UI/Main线程

if(Looper.myLooper() == Looper.getMainLooper()) {
   // Current Thread is Main Thread.
}

或者你也可以使用这个

if(Looper.getMainLooper().getThread() == Thread.currentThread()) {
   // Current Thread is Main Thread.
}

这里有一个类似的问题


10
考虑到任意线程是否与Looper相关联并没有保证(假设主线程始终与Looper相关联),因此是否应该将后者视为更安全的选项? - Janus Varmarken
1
如果线程没有与Looper相关联,Looper.myLooper()将返回null。因此,两者都是安全的并且具有相同的结果,但第一个稍微慢一些,因为它在地图中搜索以查找looper及其关联的线程并执行其他操作。 - Saeed Masoumi

74

最好的方式是最清晰、最健壮的方式:

Thread.currentThread().equals( Looper.getMainLooper().getThread() )

或者,如果运行时平台是API级别23(棉花糖6.0)或更高:

Looper.getMainLooper().isCurrentThread()

请查看Looper API。请注意,调用Looper.getMainLooper()需要同步(请参见源代码)。您可能希望通过存储返回值并重复使用来避免开销。

   * 鸣谢greg7gkb2cupsOfTech


"under API 23 or higher" 是什么意思?我不太明白。而且下面AAnkit也发了完全相同的答案。 - Mike
1
@Mike 谢谢,我已经修复了 API 部分。事实上 Ankit 更喜欢 Looper.myLooper() == Looper.getMainLooper(),但我认为这样不够清晰。我要感谢 greg7gkb。 - Michael Allan
2
这应该是一个与“==”还是“equals()”的比较,因为Android Studio正在发出警告? - 2cupsOfTech
1
@2cupsOfTech 仔细想想,这是个好建议。目前两个测试在运行时是相同的,因为 Thread 没有覆盖 equals 方法,所以会退回到 ==,但这可能会在未来发生改变。因此,我已经更正了答案。 - Michael Allan

28

总结这些解决方案,我认为这是最好的一个:

boolean isUiThread = VERSION.SDK_INT >= VERSION_CODES.M 
    ? Looper.getMainLooper().isCurrentThread()
    : Thread.currentThread() == Looper.getMainLooper().getThread();

如果您希望在UI线程上运行某些内容,您可以使用以下方法:

new Handler(Looper.getMainLooper()).post(new Runnable() {
    @Override
    public void run() {
       //this runs on the UI thread
    }
});

其他关于Handler的答案建议使用“.postDelayed()”而不是“.post()”。主要区别是什么,您能否说明为什么建议使用“.post()”? - AJW
@AJW 当然,这里是文档链接:https://developer.android.com/reference/android/os/Handler#post(java.lang.Runnable) 和 https://developer.android.com/reference/android/os/Handler#postDelayed(java.lang.Runnable,%20java.lang.Object,%20long)。如果您希望可运行的内容至少从现在开始运行X毫秒,则使用postDelayed。 - android developer
非常好,感谢提供信息。 - AJW
@androiddeveloper 我该如何在非主线程中运行某些东西? - KJEjava48
@KJEjava48 有很多方法可以实现。基本的方法是创建一个新的 Thread 类并在其上实现 run 或提供一个 Runnable 实例,然后在此 Thread 实例上调用 start()。在 Kotlin 中,有一种非常简短的方法来实现它,只需使用 thread{ runCodeHere() } 即可。 - android developer

7

您可以检查

if(Looper.myLooper() == Looper.getMainLooper()) {
   // You are on mainThread 
}else{
// you are on non-ui thread
}

4

首先检查它是否是主线程

在 Kotlin 中

fun isRunningOnMainThread(): Boolean {
    return Thread.currentThread() == Looper.getMainLooper().thread
}

在Java中
static boolean isRunningOnMainThread() {
  return Thread.currentThread().equals(Looper.getMainLooper().getThread());
}

4

首先声明一下: 我知道这篇文章有“Android”标签,但我的搜索和“Android”无关,这仅仅是我的搜索结果。因此,对于来到这里的非Android的SO Java用户,请别忘了:

public static void main(String[] args{
    Thread.currentThread().setName("SomeNameIChoose");
    /*...the rest of main...*/
}

设置之后,在代码的其他位置,您可以轻松地检查是否即将在主线程上执行:

if(Thread.currentThread().getName().equals("SomeNameIChoose"))
{
    //do something on main thread
}

有点不好意思,我在记起来之前先搜索了一下,但希望这会有助于其他人!

3
除了之前的回答外,还有以下补充:
inline fun <T> ensureNotOnMainThread(block: () -> T): T {
    check(Thread.currentThread() != Looper.getMainLooper().thread) { "This function cannot be called on main thread" }
    return block()
}

它允许将任何方法与其包装在一起,以下是示例:

fun isInDataBase(id: String) = ensureNotOnMainThread { db.contains(id) }

2

只需记录此行,它应该打印"main"。

Thread.currentThread().name


1

您可以在Android DDMS Logcat中验证它,其中进程ID将相同,但线程ID将不同。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接