Подтвердить что ты не робот

Android: почему я не могу создать обработчик в новом потоке

У меня была проблема с созданием обработчика в новой теме. Это мой код:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    new Thread(new Runnable() {
        public void run() {
            Handler handler = new Handler();
        }
    }).start();
}

Но это вызвало ошибку! Может кто-нибудь, пожалуйста, объясните мне это? Спасибо!

Вот подробности моей ошибки:

09-17 18:05:29.484: E/AndroidRuntime(810): FATAL EXCEPTION: Thread-75
09-17 18:05:29.484: E/AndroidRuntime(810): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
09-17 18:05:29.484: E/AndroidRuntime(810):  at android.os.Handler.<init>(Handler.java:197)
09-17 18:05:29.484: E/AndroidRuntime(810):  at android.os.Handler.<init>(Handler.java:111)
09-17 18:05:29.484: E/AndroidRuntime(810):  at com.example.handler.MainActivity$1.run(MainActivity.java:57)
09-17 18:05:29.484: E/AndroidRuntime(810):  at java.lang.Thread.run(Thread.java:856)
4b9b3361

Ответ 1

Вы также можете использовать HandlerThread следующим образом:

HandlerThread thread = new HandlerThread("MyHandlerThread");
thread.start();
Handler handler = new Handler(thread.getLooper());

HandlerThread имеют связанный с ними Looper, поэтому это не вызовет исключения.

Ответ 2

Поток lifecycle завершается сразу после возврата метода. Но поскольку вы создаете Handler в этом thread, обработчику нужен поток, который будет запущен, чтобы он получал сообщения и обрабатывал их.

Итак, чтобы это произошло, запустить метод не следует. Следовательно, вам нужен Looper, чтобы ждать бесконечно и обрабатывать сообщения, которые поступают в Handler.

new Thread(new Runnable() {
        public void run() {
            Looper.prepare();
            Handler handler = new Handler();
            Looper.loop();
        }
    }).start();

Ответ 3

Краткий ответ: поскольку поток, к которому вы пытаетесь присоединить обработчик, не имеет циклытеля. И поэтому конструктор класса Handler создает исключение. Вместо этого вы могли бы использовать класс HandlerThread. Это просто удобный класс, предоставляемый платформой Android.

Пожалуйста, прочитайте ниже о том, что происходит под капотом.

Давайте сначала попробуем обсудить все части по отдельности.

  1. Нить:

а. Поток - это просто поток выполнения. Предполагается, что поток по умолчанию просто выполняет свой runnable (если есть) или вызывает метод run. После вызова нового Thread.start(). Поток просто умирает, и Gc'd, когда метод run выполняет все операторы, записанные в run() {----}.

б. В Android есть концепция Looper. Что в основном делает нить блокирующей. Проще говоря, это просто не дает нити умереть. Он переходит в состояние блокировки и ожидает новых сообщений, чтобы снова возобновить его выполнение.

Ниже описано, как настроить блокирующий поток, то есть поток с циклытелем.

  new Thread(new Runnable() {
    public void run() {
        Looper.prepare();
        Looper.loop();
    }
}).start();

Здесь создается поток, который не просто умирает после выполнения оператора Looper.loop(). Вместо этого он зацикливается и переходит в состояние блокировки. Теперь вы должны спросить, что означает состояние блокировки, как поток выйдет из состояния блокировки? как мне наконец выпустить эту тему сейчас? Вот где приходит Handler

  1. Обработчик:

а. Он всегда присоединяется к луперу потока, в котором создается его экземпляр.

б. Затем он обрабатывает эти сообщения потока, к которому он присоединяется.

Собираем нить и обработчики.

new Thread(new Runnable() {
        public void run() {
            Looper.prepare();
            handler = new Handler();
            Looper.loop();
        }
    }).start();

а. Как обработчик присоединяется к этому вновь созданному потоку. б. Эта нить настроена как блокирующая нить циклытеля. Так что это не умрет.

Теперь мы можем 1. Отправить сообщение на этот обработчик. 2. Размещаем работоспособность на этом обработчике.

Оба они будут выполнены в прикрепленном потоке.

У вас есть возможность либо расширить класс Handler, либо реализовать метод handleMessage (Message msg). или вы просто предоставляете реализацию Handler.Callback в конструкторе класса обработчика. В любом случае handleMessage (сообщения msg) будет вызываться в присоединенном потоке.

Чтобы выйти из цепочки, вы можете отправить сообщение определенного типа, а после получения этого сообщения вы просто вызовете Looper.myLooper(). Quit()

class LooperThread extends Thread {
   public Handler mHandler;

   public void run() {
      Looper.prepare();

      mHandler = new Handler() {
          public void handleMessage(Message msg) {
              // process incoming messages here
              if(msg.what == -1){
              Looper.myLooper().quit();
              }
          }
      };

      Looper.loop();
   }
}

Я надеюсь, что это помогло понять общую концепцию.

Ответ 4

Обработчик должен быть инициализирован в потоке Looper, или ему предоставляется Looper.

В зависимости от того, что вы хотите сделать, вы можете настроить поток как Looper следующим образом:

new Thread(new Runnable() {
    public void run() {
        Looper.prepare();
        mHandler = new Handler();
        Looper.loop();
    }
}).start();

Поскольку Looper находится в фоновом потоке, вы не можете обновить интерфейс. Вы можете альтернативно дать обработчику Looper из другого потока - в этом примере обработчик может использоваться для обновления пользовательского интерфейса:

new Thread(new Runnable() {
    public void run() {
        Handler handler = new Handler(Looper.getMainLooper());
    }
}).start();