1128

次の例外は何を意味しますか。どうすれば修正できますか?

これはコードです:

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)
4

30 に答える 30

927

Toast.makeText(...)UI スレッドから呼び出す必要があります。

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

これは、別の (重複した) SO answerからコピーして貼り付けたものです。

于 2012-03-22T02:11:59.643 に答える
794

ワーカー スレッドから呼び出しています。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();
}

その他のオプション:

を使用できますActivity.runOnUiThread()。あなたが持っている場合は簡単ですActivity

@WorkerThread
void workerThread() {
    myActivity.runOnUiThread(() -> {
        // This is where your UI code goes.
    }
}

メインルーパーに投稿することもできます。あなたが持っているのがContext.

@WorkerThread
void workerThread() {
    ContextCompat.getMainExecutor(context).execute(()  -> {
        // This is where your UI code goes.
    }
}

非推奨:

バックグラウンドで実行されているほとんどのものに適したAsyncTaskを使用できます。進行状況と完了時に呼び出すことができるフックがあります。

便利ですが、正しく使用しないとコンテキストがリークする可能性があります。これは公式に廃止されており、今後は使用しないでください。

于 2010-10-06T17:20:58.807 に答える
459

更新 - 2016

最良の代替手段は、 inがデータを担当するためRxAndroidに (特定のバインディング for RxJava)を使用することです。PMVP

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 は基本的に、 UI スレッドバックグラウンド スレッドという 2 つのスレッド タイプで動作します。アンドロイドのドキュメントによると -

この問題を解決するために、UI スレッドの外部から Android UI ツールキットにアクセスしないでください。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();

ルーパー

スレッドのメッセージ ループを実行するために使用されるクラス。デフォルトでは、スレッドにはメッセージ ループが関連付けられていません。これを作成するには、ループを実行するスレッドで 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
    }
}

ハンドラ

Handler を使用すると、スレッドの 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;
    }
});
于 2013-06-02T19:32:49.987 に答える
185

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

コトリン

Handler(Looper.getMainLooper()).post {
        Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT).show()
}

この方法の利点は、Activity または Context なしで UI コードを実行できることです。

于 2016-01-24T00:27:03.070 に答える
99

Looper がハンドラーの前に準備されていないために runtimeException が表示される場合は、これを試してください。

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

handler.postDelayed(new Runnable() {
  @Override
  public void run() {
  // Run your task here
  }
}, 1000 );
于 2014-06-13T07:26:58.543 に答える
44

私は同じ問題に遭遇しました、そしてこれが私がそれを修正した方法です:

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

お役に立てれば。

于 2011-11-30T19:35:41.393 に答える
40

エラーの理由:

ワーカー スレッドはバックグラウンド タスクを実行するためのものであり、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 メッセージをメソッドUI thread内で呼び出しているため、Toast メッセージが確実に表示されますrunOnUiThread。だからもうjava.lang.RuntimeException

于 2013-05-16T07:40:53.933 に答える
11

This is because Toast.makeText() is calling from a worker thread. It should be call from main UI thread like this

runOnUiThread(new Runnable() {
      public void run() {
        Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
      }
 });
于 2016-05-15T08:25:33.687 に答える
8

ChicoBird の回答が役に立ちました。私が行った唯一の変更は、私がしなければならなかった UIHandler の作成でした

HandlerThread uiThread = new HandlerThread("UIHandler");

エクリプスは、それ以外のものを受け入れることを拒否しました。理にかなっていると思います。

また、uiHandler明らかにどこかで定義されたクラスグローバルです。Android がこれをどのように行っているか、何が起こっているかをまだ理解しているとは言えませんが、動作することをうれしく思います。今、私はそれを研究し、Android が何をしているのか、そしてなぜこれらすべてのフープとループを通過しなければならないのかを理解できるかどうかを確認します. 助けてくれてありがとう

于 2011-12-23T13:47:05.397 に答える
4

コールバックがダイアログを表示しようとしたときに、同じ問題が発生していました。

アクティビティの専用メソッドで解決しました-アクティビティインスタンスメンバーレベルで-それを使用します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();
        }
    });
}
于 2017-01-12T20:48:36.640 に答える
0

Toast、AlertDialogsは UI スレッドで実行する必要があります。Asynctaskを使用して Android 開発で適切に使用できます。ただし、タイムアウトをカスタマイズする必要がある場合があるため、Threadsを使用しますが、スレッドでは Toast,Alertdialogs を使用することはできません。 AsyncTask.So では、 それらをポップアップするための別のHandlerが必要です。

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 秒でスリープ状態にしたい後、メインスレッド実装ハンドラーでトースト メッセージを表示したいと考えています。

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 を使用しました。同じ方法で別のメッセージを表示する必要がある場合は、Handler クラス内で switch case を使用できるためです...これが役立つことを願っています

于 2016-07-05T10:07:04.963 に答える
0

最近、この問題に遭遇しました - コンストラクターからいくつかの UI を実行する関数を呼び出そうとしたために発生していました。コンストラクターから初期化を削除すると、問題が解決しました。

于 2021-06-28T09:38:12.263 に答える