95

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

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

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 メッセージをスレッドからユーザー インターフェイスにプッシュするための回避策はありますか?

4

7 に答える 7

33

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;
        }
    });
于 2015-06-06T09:19:52.063 に答える
6

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 つの異なるものです。

于 2013-06-29T10:13:49.313 に答える
1

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

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

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

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

于 2016-08-28T13:04:01.537 に答える