web-dev-qa-db-ja.com

java.lang.RuntimeException:Looper.prepare()を呼び出していないスレッド内にハンドラーを作成できません。

スレッドを実行しているAndroidアプリがあります。 Toastメッセージをメッセージと共に表示したい。

これを行うと、次の例外が発生します。

Logcatトレース:

FATAL EXCEPTION: Timer-0 
 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$TN.<init>(Toast.Java:322)
 at Android.widget.Toast.<init>(Toast.Java:91)
 at Android.widget.Toast.makeText(Toast.Java:238) 

Toastメッセージをスレッドからユーザーインターフェイスにプッシュするための回避策はありますか?

88
Amar

バックグラウンドスレッドからToastポップアップを作成しようとしたため、この例外が発生しました。
Toastにはユーザーインターフェイスにプッシュするアクティビティが必要ですが、スレッドにはそれがありません。
したがって、1つの回避策は、スレッドに親ActivityとToastへのリンクを与えることです。

Toastメッセージを送信するスレッドに次のコードを配置します。

parent.runOnUiThread(new Runnable() {
    public void run() {
        Toast.makeText(parent.getBaseContext(), "Hello", Toast.LENGTH_LONG).show();
    }
});

このスレッドを作成したバックグラウンドスレッドで、親アクティビティへのリンクを保持します。スレッドクラスで親変数を使用します。

private static YourActivity parent;

スレッドを作成するとき、次のように、コンストラクターを介してパラメーターとして親Activityを渡します。

public YourBackgroundThread(YourActivity parent) {
    this.parent = parent;
}

これで、バックグラウンドスレッドがToastメッセージを画面にプッシュできます。

118
Eric Leschinski

Androidは基本的に2つのスレッドタイプ、つまりUIスレッドとバックグラウンドスレッドで動作します。 Androidドキュメントによると-

この問題を解決するために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

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;
        }
    });
33
kumar kundan

ここに私がやってきたことがあります:

  public void displayError(final String errorText) {
    Runnable doDisplayError = new Runnable() {
        public void run() {
            Toast.makeText(getApplicationContext(), errorText, Toast.LENGTH_LONG).show();
        }
    };
    messageHandler.post(doDisplayError);
}

これにより、メソッドをいずれかのスレッドから呼び出すことができます。

MessageHandlerは、アクティビティ内で..として宣言されています.

Handler messageHandler = new Handler();
8
Evan Langlois

http://developer.Android.com/guide/components/processes-and-threads.html から:

さらに、Android UIツールキットはスレッドセーフではありません。 そのため、ワーカースレッドからUIを操作しないでください— UIスレッドからユーザーインターフェイスを操作する必要があります。したがって、Androidのシングルスレッドモデルには2つのルールがあります。

  1. UIスレッドをブロックしないでください
  2. UIスレッドの外部からAndroid UIツールキットにアクセスしないでください

ワーカースレッドでアイドル状態を検出し、メインスレッドでトーストを表示する必要があります。

より詳細な回答が必要な場合は、コードを投稿してください。

コード発行後:

strings.xml

<string name="idleness_toast">"You are getting late do it fast"</string>

YourWorkerThread.Java

Toast.makeText(getApplicationContext(), getString(R.string.idleness_toast), 
    Toast.LENGTH_LONG).show();

AlertDialogを使用しないで、選択してください。 AlertDialogとToastは2つの異なるものです。

6
user2467078

単にBeginInvokeOnMainThread()を使用できます。デバイスのメイン(UI)スレッドでアクションを呼び出します。

Device.BeginInvokeOnMainThread(() => { displayToast("text to display"); });

それはシンプルで、私にとって完璧に機能します!

編集:C#Xamarinを使用している場合に機能します

1
Vozek
runOnUiThread(new Runnable(){
   public void run() {
     Toast.makeText(getApplicationContext(), "Status = " + message.getBody() , Toast.LENGTH_LONG).show();
   }
 });

これは私のために働く

1
umar farooq