Как проверить, не является ли текущий поток основным потоком

392

Мне нужно проверить, является ли поток, выполняющий определенный кусок кода, основным потоком (UI) или нет. Как мне этого добиться?

Charlie-Blake
источник
пример для демонстрации с потоком пример code2concept.blogspot.in/2015/02/…
nitesh

Ответы:

709
Looper.myLooper() == Looper.getMainLooper()

если это возвращает true, то вы в потоке пользовательского интерфейса!

плотский
источник
Как вы запускаете этот код в junit?
Джон Сардинья
123

Вы можете использовать приведенный ниже код, чтобы узнать, является ли текущий поток пользовательским интерфейсом / основным потоком или нет

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

или вы также можете использовать это

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

Вот похожий вопрос

AAnkit
источник
8
Следует ли рассматривать последний как более безопасный вариант, поскольку нет гарантии, что какой-либо произвольный поток связан с Looper (при условии, что основной поток всегда связан с Looper)?
Янус Вармаркен
Looper.myLooper()вернет ноль, если поток не связан с Looper. Таким образом, оба безопасны и имеют одинаковый результат, но первый немного медленнее, когда он ищет внутри карты, чтобы найти петлитель и связанный с ним поток и сделать что-то еще.
Саид Масуми
59

Лучший способ - самый ясный, самый надежный способ: *

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

Или, если рабочая среда имеет уровень API 23 (Marshmallow 6.0) или выше:

Looper.getMainLooper().isCurrentThread()

Смотрите API Looper . Обратите внимание, что вызов Looper.getMainLooper()включает синхронизацию (см. Источник ). Возможно, вы захотите избежать накладных расходов, сохраняя возвращаемое значение и используя его повторно.

   * кредит greg7gkb и 2cupsOfTech

Майкл Аллан
источник
Что вы подразумеваете под «по API 23 или выше»? Это не имеет большого смысла для меня .. Точно такой же ответ был опубликован AAnkit, ниже ..
Майк
@ Майк Спасибо, я исправил API-бит. AAnkit на самом деле одобряет Looper.myLooper() == Looper.getMainLooper(), что, я думаю, менее понятно. Я кредит greg7gkb.
Майкл Аллан
1
должно ли это быть сравнение с == или equals (), поскольку Android Studio вызывает предупреждение?
2cupsOfTech
@ 2cupsOfTech На 2-й мысли, это хороший совет. В настоящее время оба теста одинаковы во время выполнения, потому что Thread не переопределяет equalsи поэтому возвращается к нему ==, но это может измениться в будущем. Поэтому я исправил ответ.
Майкл Аллан
25

Подводя итог решениям, я думаю, что это лучшее:

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

И, если вы хотите запустить что-то в потоке пользовательского интерфейса, вы можете использовать это:

new Handler(Looper.getMainLooper()).post(new Runnable() {
    @Override
    public void run() {
       //this runs on the UI thread
    }
});
разработчик Android
источник
6

Ты можешь проверить

if(Looper.myLooper() == Looper.getMainLooper()) {
   // You are on mainThread 
}else{
// you are on non-ui thread
}
Ловекуш Вишвакарма
источник
2

Позвольте мне предвосхитить это следующим образом: я признал, что в этом сообщении есть тег «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
}

Немного смутившись, я искал, прежде чем вспомнить это, но, надеюсь, это поможет кому-то еще!

ThatOneGuy
источник
1

Вы можете проверить это в android ddms logcat, где идентификатор процесса будет таким же, но идентификатор потока будет другим.

Vishwanath.M
источник
1

Xamarin.Androidпорт: ( C#)

public bool IsMainThread => Build.VERSION.SdkInt >= BuildVersionCodes.M
    ? Looper.MainLooper.IsCurrentThread
    : Looper.MyLooper() == Looper.MainLooper;

Применение:

if (IsMainThread) {
    // you are on UI/Main thread
}
Мехди Дехани
источник
-6

Вы можете попробовать Thread.currentThread (). IsDaemon ()

Шайлендра Сингх
источник
Я не уверен, что поток пользовательского интерфейса является демоном, но я поверю вам в этом. Но как вы будете иметь значение с Daemon Thread, который я мог (но не должен) создавать.
AxelH
Я протестировал в своем веб-приложении, оно показывает, что поток пользовательского интерфейса является потоком Daemon. Я поместил некоторые точки прерывания отладки в среду затмения и проверил это. Деталь темы показана как Тема [http-bio-8080-exec-7,5, main]. Кликнул по некоторым страницам пользовательского интерфейса и проверил точку отладки.
Шайлендра Сингх
Кроме того, даже если в имени потока указано, что он показывает 'main', но вызов setDaemon (true) для объекта потока сделает его демоном.
Шайлендра Сингх
Вы не читали хорошую часть ... Я не сомневался (полностью) в том, что это Демон, я говорил, что вы не можете делать различий с другой веткой Демонов, подобной этой.
AxelH
Другими словами: основной поток может быть потоком демона, но не все потоки демона являются основным потоком. (Идентификация главной