Не удается создать обработчик внутри потока, который не вызвал Looper.prepare () - PullRequest
879 голосов
/ 06 октября 2010

Что означает следующее исключение; как я могу это исправить?

Это код:

Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);

Это исключение:

java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
     at android.os.Handler.<init>(Handler.java:121)
     at android.widget.Toast.<init>(Toast.java:68)
     at android.widget.Toast.makeText(Toast.java:231)

Ответы [ 21 ]

797 голосов
/ 22 марта 2012

Вам необходимо позвонить Toast.makeText(...) из потока пользовательского интерфейса:

activity.runOnUiThread(new Runnable() {
  public void run() {
    Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
  }
});

Это скопировано из другого (дублирующего) SO ответа .

631 голосов
/ 06 октября 2010

Вы звоните из рабочего потока.Вам необходимо вызвать Toast.makeText() (и большинство других функций, связанных с пользовательским интерфейсом) из основного потока.Вы можете использовать обработчик, например.

Поиск Связь с потоком пользовательского интерфейса в документации.В двух словах:

// Set this up in the UI thread.

mHandler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message message) {
        // This is where you do your work in the UI thread.
        // Your worker tells you in the message what to do.
    }
};

void workerThread() {
    // And this is how you call it from the worker thread:
    Message message = mHandler.obtainMessage(command, parameter);
    message.sendToTarget();
}

Другие параметры:

Можно использовать AsyncTask , который хорошо работает для большинства вещей, работающих в фоновом режиме,У него есть хуки, которые вы можете вызвать, чтобы указать прогресс, и когда это будет сделано.

Вы также можете использовать Activity.runOnUiThread () .

429 голосов
/ 02 июня 2013

ОБНОВЛЕНИЕ - 2016

Лучшая альтернатива - использовать RxAndroid (специальные привязки для RxJava) для P in MVP для сбора данных.

Начните с возврата Observable из существующего метода.

private Observable<PojoObject> getObservableItems() {
    return Observable.create(subscriber -> {

        for (PojoObject pojoObject: pojoObjects) {
            subscriber.onNext(pojoObject);
        }
        subscriber.onCompleted();
    });
}

Используйте это наблюдаемое, как это -

getObservableItems().
subscribeOn(Schedulers.io()).
observeOn(AndroidSchedulers.mainThread()).
subscribe(new Observer<PojoObject> () {
    @Override
    public void onCompleted() {
        // Print Toast on completion
    }

    @Override
    public void onError(Throwable e) {}

    @Override
    public void onNext(PojoObject pojoObject) {
        // Show Progress
    }
});
}

-------------------------------------------- -------------------------------------------------- ------------------------------------

Я знаю, что немного опаздываю, но здесь идет. Android в основном работает с двумя типами потоков, а именно UI thread и background thread . По документации андроид -

Не обращайтесь к инструментарию пользовательского интерфейса Android из-за потока пользовательского интерфейса, чтобы решить эту проблему, Android предлагает несколько способов доступа к потоку пользовательского интерфейса из других потоков. Вот список методов, которые могут помочь:

Activity.runOnUiThread(Runnable)  
View.post(Runnable)  
View.postDelayed(Runnable, long)

В настоящее время существуют различные способы решения этой проблемы.

Я объясню это примером кода:

runOnUiThread

new Thread()
{
    public void run()
    {
        myactivity.this.runOnUiThread(new Runnable()
        {
            public void run()
            {
                //Do your UI operations like dialog opening or Toast here
            }
        });
    }
}.start();

LOOPER

Класс, используемый для запуска цикла сообщений для потока. Темы по умолчанию делают не иметь связанный с ними цикл сообщений; чтобы создать его, позвоните prepare () в потоке, который должен запустить цикл, а затем loop () для пусть он обрабатывает сообщения до тех пор, пока цикл не будет остановлен.

class LooperThread extends Thread {
    public Handler mHandler;

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

        mHandler = new Handler() {
            public void handleMessage(Message msg) {
                // process incoming messages here
            }
        };

        Looper.loop();
    }
}

AsyncTask

AsyncTask позволяет вам выполнять асинхронную работу над вашим пользователем интерфейс. Он выполняет операции блокировки в рабочем потоке и затем публикует результаты в потоке пользовательского интерфейса, не требуя от вас обрабатывать темы и / или обработчики самостоятельно.

public void onClick(View v) {
    new CustomTask().execute((Void[])null);
}


private class CustomTask extends AsyncTask<Void, Void, Void> {

    protected Void doInBackground(Void... param) {
        //Do some work
        return null;
    }

    protected void onPostExecute(Void param) {
        //Print Toast or open dialog
    }
}

Обработчик

Обработчик позволяет отправлять и обрабатывать объекты Message и Runnable. связанный с MessageQueue потока.

Message msg = new Message();


new Thread()
{
    public void run()
    {
        msg.arg1=1;
        handler.sendMessage(msg);
    }
}.start();



Handler handler = new Handler(new Handler.Callback() {

    @Override
    public boolean handleMessage(Message msg) {
        if(msg.arg1==1)
        {
            //Print Toast or open dialog        
        }
        return false;
    }
});
81 голосов
/ 13 июня 2014

Попробуйте, если вы видите runtimeException из-за того, что Looper не подготовлен перед обработчиком.

Handler handler = new Handler(Looper.getMainLooper()); 

handler.postDelayed(new Runnable() {
  @Override
  public void run() {
  // Run your task here
  }
}, 1000 );
77 голосов
/ 24 января 2016

Toast.makeText() должен вызываться только из потока Main / UI. Looper.getMainLooper () помогает вам достичь этого:

new Handler(Looper.getMainLooper()).post(new Runnable() {
    @Override
    public void run() {
        Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
    }
});

Преимущество этого метода в том, что вы можете использовать его в классах без Activity (или без Context).

39 голосов
/ 30 ноября 2011

Я столкнулся с той же проблемой, и вот как я ее исправил:

private final class UIHandler extends Handler
{
    public static final int DISPLAY_UI_TOAST = 0;
    public static final int DISPLAY_UI_DIALOG = 1;

    public UIHandler(Looper looper)
    {
        super(looper);
    }

    @Override
    public void handleMessage(Message msg)
    {
        switch(msg.what)
        {
        case UIHandler.DISPLAY_UI_TOAST:
        {
            Context context = getApplicationContext();
            Toast t = Toast.makeText(context, (String)msg.obj, Toast.LENGTH_LONG);
            t.show();
        }
        case UIHandler.DISPLAY_UI_DIALOG:
            //TBD
        default:
            break;
        }
    }
}

protected void handleUIRequest(String message)
{
    Message msg = uiHandler.obtainMessage(UIHandler.DISPLAY_UI_TOAST);
    msg.obj = message;
    uiHandler.sendMessage(msg);
}

Чтобы создать UIHandler, вам необходимо выполнить следующее:

    HandlerThread uiThread = new HandlerThread("UIHandler");
    uiThread.start();
    uiHandler = new UIHandler((HandlerThread) uiThread.getLooper());

Надеюсь, это поможет.

32 голосов
/ 16 мая 2013

Причина ошибки:

Рабочие потоки предназначены для выполнения фоновых задач, и вы не можете ничего показать в пользовательском интерфейсе в рабочем потоке, если вы не вызовете метод, подобный runOnUiThread . Если вы попытаетесь что-то показать в потоке пользовательского интерфейса без вызова runOnUiThread, будет java.lang.RuntimeException.

Итак, если вы находитесь в activity, но вызываете Toast.makeText() из рабочего потока, сделайте следующее:

runOnUiThread(new Runnable() 
{
   public void run() 
   {
      Toast toast = Toast.makeText(getApplicationContext(), "Something", Toast.LENGTH_SHORT).show();    
   }
}); 

Приведенный выше код гарантирует, что вы отображаете сообщение Toast в UI thread, так как вы вызываете его внутри runOnUiThread метода. Так что не более java.lang.RuntimeException.

21 голосов
/ 20 ноября 2014

Я получал эту ошибку, пока не сделал следующее.

public void somethingHappened(final Context context)
{
    Handler handler = new Handler(Looper.getMainLooper());
    handler.post(
        new Runnable()
        {
            @Override
            public void run()
            {
                Toast.makeText(context, "Something happened.", Toast.LENGTH_SHORT).show();
            }
        }
    );
}

И сделал это в одном классе:

public enum Toaster {
    INSTANCE;

    private final Handler handler = new Handler(Looper.getMainLooper());

    public void postMessage(final String message) {
        handler.post(
            new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(ApplicationHolder.INSTANCE.getCustomApplication(), message, Toast.LENGTH_SHORT)
                        .show();
                }
            }
        );
    }

}
19 голосов
/ 16 марта 2017

вот что я сделал.

new Handler(Looper.getMainLooper()).post(new Runnable() {
    @Override
    public void run() {
        Toast(...);
    }
});

Визуальные компоненты «заблокированы» для изменений извне потоков. Итак, так как тост показывает материал на главном экране, которым управляет основной поток, вам нужно запустить этот код в этом потоке. Надеюсь, это поможет:)

8 голосов
/ 15 мая 2016

Это потому, что Toast.makeText () вызывается из рабочего потока. Это должен быть вызов из основного потока пользовательского интерфейса, как это

runOnUiThread(new Runnable() {
      public void run() {
        Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
      }
 });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...