getLooper() возвращает null после запуска HandlerThread

У меня есть класс extends HandlerThread, он выглядит так:

public class MyHandlerThread extends HandlerThread {

  private Object lock;

  //constructor
  public MyHandlerThread() {
     super(“MyHandlerThread”);
     lock = new Object();
  }

  public void prepare() {
     //starts the handler thread
     start();

     //Wait for thread starting
     Log.d(TAG, "wait for thread starting…");
     synchronized (lock) {
        try {
            lock.wait(5000);
        } catch (InterruptedException e) {
            Log.e(TAG, "Failed to wait for thread to start");
        }
     }

     //WHY getLooper() returns null here?
     if(getLooper() == null) {
         Log.d("GET LOOPER NULL!");
     }
  }

  @Override
  public void run() {
    Log.d("run() begin...");
    initializeSomeObjects()
    Log.d(“initialise objects done!”);

    //Notify that run() finished
    synchronized (lock) {
       lock.notify();
    }
    Log.d("run() end!”);
  }

}

Как вы видите выше, функция prepare() запускает поток и ждет завершения run(), а затем пытается получить цикл.

В другом классе я создаю экземпляр MyHandlerThread и запускаю его:

MyHandlerThread myThread = new MyHandlerThread();
myThread.prepare();

Журналы, отображаемые в консоли:

wait for thread starting…
run() begin...
initialise objects done!
run() end!
GET LOOPER NULL!

Почему в функции prepare() вызов getLooper() возвращает null, хотя поток уже запущен (выполняется run())?


person user842225    schedule 08.10.2015    source источник
comment
1) создать новый HandlerThread: HandlerThread ht = new HandlerThread("foo"); 2) запустить его 3) сделать Handler: Handler h = new Handler(ht.getLooper()) {... 4) отправить Messages: h.sendEmptyMessage(999)   -  person pskink    schedule 08.10.2015
comment
Спасибо, я нашел то же самое в гугле, но почему с моим подходом getLooper() равно NULL? Мой код выглядит так, как если бы я выполнял те же шаги, с той лишь разницей, что я запускаю поток внутри класса.   -  person user842225    schedule 08.10.2015
comment
на самом деле есть 3 шага, чтобы сделать Handler / HandlerThread готовыми, и один, чтобы установить Messages... зачем усложнять? почему вы хотите расширить HandlerThread ?   -  person pskink    schedule 08.10.2015
comment
Я действительно хочу знать причину. Это способ понять, что происходит внизу, не так ли? Просто заставить его работать - это не моя точка зрения, поэтому я говорю, что нашел ваше предложение и в Google.   -  person user842225    schedule 08.10.2015
comment
поэтому, если вы хотите узнать, что находится внизу, посмотрите здесь   -  person pskink    schedule 08.10.2015
comment
и вот мой ответ на аналогичный вопрос: stackoverflow.com/a/25096981/2252830   -  person pskink    schedule 08.10.2015
comment
кстати, если вы хотите выполнить какое-то действие (initializeSomeObjects) в вызывающем потоке, сделайте это в prepare перед запуском HandlerThread, и если вы хотите сделать это в фоновом потоке, просто переопределите onLooperPrepared, который вызывается прямо перед вызовом Looper.loop()   -  person pskink    schedule 09.10.2015


Ответы (1)


HandlerThread Looper инициализируется в HandlerThread#run().

Если вы переопределяете метод и не вызываете super.run(), код инициализации из суперкласса не выполняется.

person laalto    schedule 08.10.2015
comment
не совсем: метод getLooper() возвращает Looper, связанный с этим HandlerThread, кстати, он вызывает его из потока пользовательского интерфейса, а поток пользовательского интерфейса имеет Looper, не так ли? - person pskink; 08.10.2015
comment
@pskink Спасибо, упустил из виду тот факт, что это было HandlerThread#getLooper(), а не, например. Looper#myLooper(). Ответ переписан. - person laalto; 09.10.2015