次の例外はどういう意味ですか。どうすれば修正できますか?
これはコードです:
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)
あなたはそれをワーカースレッドから呼び出しています。メインスレッド内からToast.makeText()
(およびUIを扱う他のほとんどの関数)を呼び出す必要があります。たとえば、ハンドラを使うことができます。
ドキュメント内の 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 を使用することもできます。これは、バックグラウンドで実行されているほとんどのものに適しています。それはあなたが進歩を示すために、そしてそれがいつ終わったかを示すために呼ぶことができるフックを持っています。
Activity.runOnUiThread() を使用することもできます。
UIスレッドからToast.makeText(...)
を呼び出す必要があります。
activity.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
}
});
これは another(duplicate)SO answer からコピー&ペーストされます。
最善の方法は、データを管理するために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は基本的に2つのスレッドタイプ、つまり UIスレッド と バックグラウンドスレッド で動作します。 Androidのドキュメントによると -
この問題を解決するためにUIスレッドの外側からAndroid UIツールキットにアクセスしないでください。Androidでは、他のスレッドからUIスレッドにアクセスする方法がいくつかあります。これは助けることができる方法のリストです:
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
現在、この問題を解決するためのさまざまな方法があります。
コードサンプルで説明します。
new Thread()
{
public void run()
{
myactivity.this.runOnUiThread(new Runnable()
{
public void run()
{
//Do your UI operations like dialog opening or Toast here
}
});
}
}.start();
スレッドに対してメッセージループを実行するために使用されるクラス。デフォルトでは、スレッドにはメッセージループが関連付けられていません。作成するには、ループを実行するスレッドで 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を使用すると、ユーザーインターフェイスで非同期作業を実行できます。それはワーカースレッドでブロッキング操作を実行し、それからあなたが[/。]あなた自身でスレッドやハンドラーを処理することを要求することなく、UIスレッドで結果を公開します。
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
}
}
ハンドラを使用すると、スレッドのMessageQueueに関連付けられているMessageオブジェクトおよびRunnableオブジェクトを送信して処理できます。
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;
}
});
LooperによるruntimeExceptionがハンドラの前に準備されていない場合にこれを試してください。
Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
@override
void run() {
// Run your task here
}
}, 1000 );
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なしの)クラスでも使用できることです。
私は同じ問題に出くわしました、そして、私はそれをどのように修正したかです:
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());
お役に立てれば。
エラーの理由:
ワーカースレッドはバックグラウンドタスクを実行するためのものであり、 runOnUiThread のようなメソッドを呼び出さない限り、ワーカースレッド内のUIには何も表示できません。 runOnUiThreadを呼び出さずにUIスレッドに何かを表示しようとすると、Java.lang.RuntimeException
が表示されます。
あなたがactivity
にいるがワーカースレッドからToast.makeText()
を呼び出しているのであれば、こうします:
runOnUiThread(new Runnable()
{
public void run()
{
Toast toast = Toast.makeText(getApplicationContext(), "Something", Toast.LENGTH_SHORT).show();
}
});
上記のコードは、ToastメッセージをrunOnUiThread
メソッド内で呼び出しているので、UI thread
でToastメッセージを表示していることを確認します。だから、もう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(...);
}
});
ビジュアルコンポーネントは、外部スレッドからの変更に「ロック」されています。したがって、トーストはメインスレッドで管理されているものをメイン画面に表示するため、このコードをそのスレッドで実行する必要があります。 ] :)それが役立つことを願っています
これは、Toast.makeText()がワーカースレッドから呼び出しているためです。このようにメインUIスレッドから呼び出す必要があります
runOnUiThread(new Runnable() {
public void run() {
Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
}
});
ChicoBirdによる答えは私のために働きました。私がした唯一の変更は、私がしなければならなかったUIHandlerの作成でした。
HandlerThread uiThread = new HandlerThread("UIHandler");
Eclipseは他に何かを受け入れることを拒否しました。私が思うに理にかなっています。
またuiHandler
は明らかにどこかで定義されたグローバルクラスです。私はまだAndroidがこれをやっているのか、そして何が起こっているのかを理解しているとは主張していませんが、私はそれがうまくいってうれしいです。それでは、私はそれを勉強して、Androidが何をしているのか、そしてなぜこれらすべてのフープやループを通過しなければならないのか理解できるかどうかを確かめます。助けChicoBirdをありがとう。
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(mContext, "Message", Toast.LENGTH_SHORT).show();
}
});
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の専用メソッドを使ってそれを解決しました - 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();
}
});
}
素晴らしいコトリンソリューション:
runOnUiThread {
// Add your ui thread code here
}
ダイアログやトースターをスレッドで表示するには、最も簡潔な方法は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、AlertDialogs はUIスレッドで実行する必要があります。 Asynctask を使用してAndroid開発で正しく使用することができます。ただし、タイムアウトをカスタマイズする必要がある場合は Threads 、しかし、スレッドではToastを使用できません。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クラス内でスイッチケースを使用することができます。
これは通常、メインスレッド上の何かがバックグラウンドスレッドから呼び出されたときに起こります。例を見てみましょう。
private class MyTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... voids) {
textView.setText("Any Text");
return null;
}
}
上記の例では、メインUIスレッドにあるtextviewに、ワーカースレッドでのみ動作するdoInBackground()メソッドからテキストを設定しています。
Handler handler2;
Thread second_thread=new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
handler2=new Handler();
}
});
second_thread.start();
これでhandler2はおそらくメインスレッドとは異なるスレッドを使ってメッセージを処理します。
最初にLooper.prepare()
を呼び出し、次にToast.makeText().show()
を呼び出し、最後にLooper.loop()
を呼び出します。
Looper.prepare() // to be able to make toast
Toast.makeText(context, "not connected", Toast.LENGTH_LONG).show()
Looper.loop()
私は同じ問題を抱えていて、ToastをAsynctask <>のonPostExecute()オーバーライド関数に入れることによってそれを修正しました、そしてそれは働きました。