Не могу создать обработчик внутри потока, который не называется лупер.подготовить()
что означает следующее исключение; как я могу это исправить?
этот код:
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)
19 ответов:
вы вызываете его из рабочего потока. Вам нужно позвонить
Toast.makeText()
(и большинство других функций, связанных с UI) из основного потока. Вы можете использовать обработчик, например.посмотреть связь с потоком пользовательского интерфейса в документации. В двух словах:
// 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, который хорошо работает для большинства вещей, работающих в фоновом режиме. Он имеет крючки, которые вы можете позвонить, чтобы указать прогресс, и когда это будет сделано.
вы также можете использовать активности.runOnUiThread().
нужно позвонить
Toast.makeText(...)
из потока пользовательского интерфейса:activity.runOnUiThread(new Runnable() { public void run() { Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show(); } });
это копировать-вставить из другой (дубликат) так ответ.
обновление - 2016
лучшая альтернатива-использовать
RxAndroid
(конкретные привязки дляRxJava
) дляP
наMVP
чтобы взять на себя ответственность за данные fo.начать с возвращения
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 и фоновый поток. Согласно документации android -
не получить доступ к Android UI toolkit из-за пределов потока пользовательского интерфейса, чтобы чтобы исправить эту проблему, Android предлагает несколько способов доступа к UI-потоку из других потоков. Вот список методов, которые могут помочь:
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
класс, используемый для запуска цикла сообщений для потока. Темы по умолчанию не иметь цикл сообщений, связанный с ними; создайте один, позвоните подготовьте() в потоке, который должен выполнить цикл, а затем цикл () к пусть он обрабатывает сообщения до тех пор, пока цикл не будет остановлен.
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 } }
проводник
обработчик позволяет отправлять и обрабатывать сообщения и 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; } });
попробуйте это, когда вы видите runtimeException из-за Looper не подготовлен перед обработчиком.
Handler handler = new Handler(Looper.getMainLooper()); handler.postDelayed(new Runnable() { @override void run() { // Run your task here } }, 1000 );
я столкнулся с той же проблемой, и вот как я ее исправил:
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());
надеюсь, что это помогает.
Toast.makeText()
должен быть вызван из главного потока / UI.Looper.getMainLooper()
помогает вам достичь этого:new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT); } });
преимущество этого метода заключается в том, что вы можете использовать его в классах без активности (или без контекста).
причина ошибки:
рабочие потоки предназначены для выполнения фоновых задач, и вы не можете ничего показать в пользовательском интерфейсе в рабочем потоке, если вы не вызываете метод, например runOnUiThread. Если вы попытаетесь показать что-либо в потоке пользовательского интерфейса без вызова runOnUiThread, будет
java.lang.RuntimeException
.Итак, если вы находитесь в
activity
но вызовToast.makeText()
из рабочего потока, сделать это:runOnUiThread(new Runnable() { public void run() { Toast toast = Toast.makeText(getApplicationContext(), "Something", Toast.LENGTH_SHORT).show(); } });
приведенный выше код гарантирует, что вы отображение тост-сообщения в
UI thread
так как вы называете его внутриrunOnUiThread
метод. Так что больше неjava.lang.RuntimeException
.
Я получал эту ошибку, пока не сделал следующее.
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(); } } ); } }
вот что я сделал.
new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { Toast(...); } });
визуальные компоненты "заблокированы" для изменений из внешних потоков. Итак, поскольку тост показывает материал на главном экране, который управляется основным потоком, вам нужно запустить этот код в этом потоке. Надеюсь, что это поможет:)
Это потому что гренка.makeText () вызывает из рабочего потока. Это должен быть вызов из основного потока пользовательского интерфейса, как это
runOnUiThread(new Runnable() { public void run() { Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT); } });
ответ ChicoBird работал для меня. Единственное изменение, которое я сделал, было в создании UIHandler, где я должен был сделать
HandlerThread uiThread = new HandlerThread("UIHandler");
затмение отказалось принять что-либо еще. Полагаю, это имеет смысл.
и
uiHandler
явно глобальный класс, определенный где-то. Я все еще не утверждаю, что понимаю, как Android делает это и что происходит, но я рад, что это работает. Теперь я перейду к его изучению и посмотрю, могу ли я понять, что делает Android и почему один приходится проходить через все эти обручи и петли. Спасибо за помощь ChicoBird.
я столкнулся с той же проблемой, когда мои обратные вызовы будут пытаться показать диалог.
Я решил это с помощью специальных методов в Activity-at the 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(); } }); }
для пользователя 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(); }); }
для отображения диалогового окна или тостера в потоке наиболее сжатым способом является использование объекта 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() ...
runOnUiThread(new Runnable() { public void run() { Toast.makeText(mContext, "Message", Toast.LENGTH_SHORT).show(); } });
Тост, AlertDialogs должен работать в потоке пользовательского интерфейса, вы можете использовать Asynctask чтобы правильно использовать их в разработке android.но в некоторых случаях нам нужно настроить тайм-ауты, поэтому мы используем Threads, но в потоках мы не можем использовать тосты, Alertdialogs, как мы используем в AsyncTask.So нам нужен отдельный проводник для всплывающем те.
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(); }
В приведенном выше примере я хочу спать мой поток в 3sec и после того, как я хочу, чтобы показать тост сообщение,что в 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); } };
я использовал switch case здесь, потому что если вам нужно показать другое сообщение таким же образом, вы можете использовать switch case в классе обработчика...надеюсь, это поможет вам
это обычно происходит, когда что-то в главном потоке вызывается из любого фонового потока. Рассмотрим пример , например.
private class MyTask extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... voids) { textView.setText("Any Text"); return null; } }
в приведенном выше примере мы устанавливаем текст в textview, который находится в основном потоке пользовательского интерфейса из метода doInBackground (), который работает только в рабочем потоке.
сначала нужно импортировать заданную строку.
import android.os.StrictMode;
и затем добавить ниже строки
onCreate()
способ Вашей деятельности:StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy);
Я использую следующий код, чтобы показать сообщение из не основного потока "контекст",
@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(); } }