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

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

Это код:

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)
 Oleksii K.14 июл. 2015 г., 21:23
да, но это очень полезная оболочка
 Dheeraj Bhaskar25 авг. 2014 г., 17:49
Что за глупое сообщение об ошибке! Это могло бы быть так же просто, как - нельзя вызывать это из потока, не являющегося пользовательским интерфейсом, как это было сделано при касании представлений из потока, не являющегося пользовательским интерфейсом.
 Helin Wang14 июл. 2015 г., 21:21
@OleksiiKropachov реализация библиотеки, которую вы упомянули, очень похожа на выполнение runOnUiThread ().
 Oleksii K.17 июл. 2014 г., 12:13
проверить эту библиотекуcompile 'com.shamanland:xdroid-toaster:0.0.5'не требуетrunOnUiThread() или жеContext Переменная, все рутина ушла! просто вызватьToaster.toast(R.string.my_msg); вот пример:github.com/shamanland/xdroid-toaster-example
 Helin Wang14 июл. 2015 г., 20:48
Для тех, кто получает одно и то же сообщение об исключении из другого кода: сообщение об исключении означает, что вы вызываете код через поток, который не подготовил Looper. Обычно это означает, что вы не звоните, если из потока пользовательского интерфейса, но вы должны (в случае OP) - нормальный поток не подготавливает Looper, но поток пользовательского интерфейса всегда делает.

Ответы на вопрос(20)

Ответ от ChicoBird работал для меня. Единственное изменение, которое я сделал, было в создании UIHandler, где я должен был сделать

HandlerThread uiThread = new HandlerThread("UIHandler");

Затмение отказалось принять что-либо еще. Имеет смысл, я полагаю.

Так жеuiHandler явно глобальный класс, определенный где-то. Я до сих пор не утверждаю, что понимаю, как Android это делает и что происходит, но я рад, что это работает. Теперь я приступлю к его изучению и выясню, могу ли я понять, что делает Android и почему нужно пройти через все эти обручи и петли. Спасибо за помощь ChicoBird.

Это обычно происходит, когда что-то в основном потоке вызывается из какого-либо фонового потока. Давайте рассмотрим пример, например.

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


@Override
protected Void doInBackground(Void... voids) {
        textView.setText("Any Text");
        return null;
    }
}

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

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

Рабочие потоки предназначены для выполнения фоновых задач, и вы не можете ничего показать в пользовательском интерфейсе в рабочем потоке, если вы не вызовете метод, подобный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.

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 (или без контекста).

 cabaji9902 окт. 2017 г., 22:38
Спасибо, другие ответы не работали на меня. Я использую запись сахара в библиотеке для управления сохранением. И внутри меня нет активности. Но это прекрасно работает

Для пользователей Rxjava и RxAndroid:

public static void shortToast(String msg) {
    Observable.just(msg)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(message -> {
                Toast.makeText(App.getInstance(), message, Toast.LENGTH_SHORT).show();
            });
}
 Borja23 окт. 2017 г., 21:47
Эти скобки не нужны

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

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());

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

 Shaun Neal30 сент. 2013 г., 02:55
+1 за код, который использует «супер петлитель»
 Nick Kahn29 февр. 2012 г., 04:41
Я пытался использовать ваш код, но я потерял и не знаю, как позвонить сonCreate method или из AsyncTask в моей ситуации, пожалуйста, опубликуйте весь код, чтобы узнать, как все работает?
 Beer Me09 сент. 2013 г., 18:42
Разве эта последняя строка не должна читатьсяuiHandler = new UIHandler(uiThread.getLooper()); ?

Чтобы отобразить диалог или тостер в потоке, наиболее кратким способом является использование объекта Activity.

Например:

new Thread(new Runnable() {
    @Override
    public void run() {
        myActivity.runOnUiThread(new Runnable() {
            public void run() {
                myActivity.this.processingWaitDialog = new ProgressDialog(myActivity.this.getContext());
                myActivity.this.processingWaitDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
                myActivity.this.processingWaitDialog.setMessage("abc");
                myActivity.this.processingWaitDialog.setIndeterminate(true);
                myActivity.this.processingWaitDialog.show();
            }
        });
        expenseClassify.serverPost(
                new AsyncOperationCallback() {
                    public void operationCompleted(Object sender) {
                        myActivity.runOnUiThread(new Runnable() {
                            public void run() {
                                if (myActivity.this.processingWaitDialog != null 
                                        && myActivity.this.processingWaitDialog.isShowing()) {
                                    myActivity.this.processingWaitDialog.dismiss();
                                    myActivity.this.processingWaitDialog = null;
                                }
                            }
                        }); // .runOnUiThread(new Runnable()
...
Решение Вопроса

Вы звоните из рабочего потока. Вам нужно позвонить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 ().

 Masoud Dadashi18 дек. 2015 г., 19:37
@aloneguid: ответ полностью связан. это было несправедливо ...
 cdata01 мар. 2013 г., 23:55
Просто добавляю мои два цента к тому, что сказал Клегги. Было бы предпочтительнее дать краткую демонстрацию того, что вы имеете в виду (хотя и надуманный), поскольку закодированный пример часто говорит сам за себя.
 Ivan G.05 июл. 2011 г., 20:29
как насчет оригинальной проблемы (это не было о AlertDialog)?
 Anand Savjani31 мая 2018 г., 19:31
этот ответ не очень полезен, немного сложен
 tony909926 сент. 2013 г., 09:50
для полного технического ответа см. этоprasanta-paul.blogspot.kr/2013/09/...
 A Droid13 февр. 2019 г., 21:07
Я хотел бы, чтобы код был завершен, чтобы я мог увидеть полный пример.
 Ahmed18 апр. 2014 г., 02:50
Почти во всех языках программирования AFAIK, которые поддерживают GUI, если вы обновляете / изменяете / отображаете / взаимодействуете с GUI напрямую, это следует делать в основном потоке программы.
 Scruffy31 июл. 2016 г., 12:32
(and most other functions dealing with the UI) Пример функции пользовательского интерфейса, используемой из фона:android.support.design.widget.Snackbar - его функциональность не уменьшается, если не вызывать из потока пользовательского интерфейса.
Handler handler2;  
HandlerThread handlerThread=new HandlerThread("second_thread");
handlerThread.start();
handler2=new Handler(handlerThread.getLooper());

Теперь handler2 будет использовать другой поток для обработки сообщений, отличный от основного потока.

я использую следующий код, чтобы показать сообщение из не основного потока "контекста",

@FunctionalInterface
public interface IShowMessage {
    Context getContext();

    default void showMessage(String message) {
        final Thread mThread = new Thread() {
            @Override
            public void run() {
                try {
                    Looper.prepare();
                    Toast.makeText(getContext(), message, Toast.LENGTH_LONG).show();
                    Looper.loop();
                } catch (Exception error) {
                    error.printStackTrace();
                    Log.e("IShowMessage", error.getMessage());
                }
            }
        };
        mThread.start();
    }
}

затем используйте как следующее:

class myClass implements IShowMessage{

  showMessage("your message!");
 @Override
    public Context getContext() {
        return getApplicationContext();
    }
}

Тост, AlertDialogs необходимо запустить в потоке пользовательского интерфейса, вы можете использоватьAsyncTask чтобы использовать их должным образом в разработке Android. Но в некоторых случаях нам нужно настроить время ожидания, поэтому мы используемПотоки, но в потоках мы не можем использовать Toast, Alertdialogs, как мы используем в AsyncTask. Так что нам нужно отдельноукротитель для всплывающих тем.

public void onSigned() {
    Thread thread = new Thread(){
        @Override
        public void run() {
            try{
                sleep(3000);
                Message message = new Message();
                message.what = 2;
                handler.sendMessage(message);
            } catch (Exception e){
                e.printStackTrace();
            }
        }
    };
    thread.start();
}

В приведенном выше примере я хочу спать мой поток в 3 секунды, и после того, как я хочу показать сообщение Toast, для этого в вашемmainthread реализовать обработчик.

handler = new Handler() {
       public void handleMessage(Message msg) {
           switch(msg.what){
              case 1:
              Toast.makeText(getActivity(),"cool",Toast.LENGTH_SHORT).show();
              break;
           }
           super.handleMessage(msg);
       }
};

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

это то, что я сделал.

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

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

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

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

handler.postDelayed(new Runnable() {
  @override
  void run() {
  // Run your task here
  }
}, 1000 );
 IgorGanapolsky02 февр. 2017 г., 23:51
Это не может быть проблемой. Петель может не существовать из вызывающего класса, точка.
 Stealth Rabbi11 дек. 2014 г., 19:37
Обработчик - это абстрактная классика. это не компилируется
 NightFury17 февр. 2015 г., 08:58
@StealthRabbi Импорт обработчика из правильного пространства имен, т.е.android.os.Handler

Я столкнулся с той же проблемой, когда мои обратные вызовы пытались показать диалог.

Я решил это с помощью специальных методов в Activity - в Activityуровень члена экземпляра - что использоватьrunOnUiThread(..)

public void showAuthProgressDialog() {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            mAuthProgressDialog = DialogUtil.getVisibleProgressDialog(SignInActivity.this, "Loading ...");
        }
    });
}

public void dismissAuthProgressDialog() {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            if (mAuthProgressDialog == null || ! mAuthProgressDialog.isShowing()) {
                return;
            }
            mAuthProgressDialog.dismiss();
        }
    });
}

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

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

У меня была та же проблема, и я исправил ее, просто поместив Toast в функцию переопределения onPostExecute () в Asynctask <>, и это сработало.

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

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

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

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

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

Используйте это Observable, как это -

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 в основном работает на двух типах потоков, а именноПользовательский интерфейс а такжефон, поток, Согласно документации Android -

Не обращайтесь к инструментарию пользовательского интерфейса 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;
    }
});
 WeSt08 авг. 2017 г., 10:59
Я использую doInBackground и хочу получить ArrayList, но всегда получаю сообщение об ошибке: не могу создать обработчик внутри потока, который не вызвал Looper.prepare (). Смотри это мой вопросstackoverflow.com/questions/45562615/... но я не могу получить решение из этого ответа здесь
 Jerry Abraham31 дек. 2018 г., 09:11
Могу ли я открыть форму или занятие вместо Print Toast или открыть диалог?
 Fenix Voltres15 апр. 2015 г., 11:13
Спасибо, 5 лет Android-программирования и я никогда не зналView также есть методыpost(Runnable) а такжеpostDelayed(Runnable, long)! Так много хендлеров напрасно. :)
 Navin03 нояб. 2013 г., 03:19
Этоименно так что я искал Особенно первый пример сrunOnUiThread
 Helin Wang14 июл. 2015 г., 20:44
для тех, кто смущен примером обработчика: с каким потоком связан новый обработчик (обратный вызов)? Это связано с потоком, который создал обработчик.
 anand krish29 мар. 2018 г., 12:23
Это элегантно, чтобы показать тост по-разному в не-пользовательском интерфейсе. @Mjosh
 Zeek Aran14 февр. 2018 г., 17:59
Спустя годы это было то, что я искал. Спасибо. observeOn (AndroidSchedulers.mainThread ()).
 IgorGanapolsky02 февр. 2017 г., 23:50
Почему этолучшая альтернатива?
 runOnUiThread(new Runnable() {
            public void run() {
                Toast.makeText(mContext, "Message", Toast.LENGTH_SHORT).show();
            }
        });
 Black_Zerg06 янв. 2019 г., 16:22
Это сработало для меня, и я использую лямбдуrunOnUiThread(() -> { Toast toast = Toast.makeText(getApplicationContext(), "Message", Toast.LENGTH_SHORT); toast.show(); });

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

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();
                }
            }
        );
    }

}
 IgorGanapolsky03 февр. 2017 г., 00:05
Где вы используетеТостер? В вашем первом фрагменте он не используется ...
 EpicPandaForce03 февр. 2017 г., 15:23
Статическая переменнаяCustomApplication установить вCustomApplication.onCreate()учитывая, что приложение всегда существует, а процесс существует, этот контекст можно использовать глобально
 EpicPandaForce03 февр. 2017 г., 00:12
это был удобный класс, который я использовал какToaster.INSTANCE.postMessage(ResourceUtils.getString(R.string.blah)); (долго я знаю! мы сократили это позже), хотя я некоторое время не использовал тосты
 IgorGanapolsky03 февр. 2017 г., 15:23
Так что жеApplicationHolder.INSTANCE оценить?

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

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

Это скопировано сдругой (дубликат) ТАК ответ.

 Cen9211 мая 2014 г., 14:24
Отличный ответ. Это меня немного смутило. Просто чтобы заметить, мне не нужно было активности. перед запуском OnUiThread.

Ваш ответ на вопрос