簡體   English   中英

如何在 Android 上顯示來自后台線程的 Toast?

[英]How do you display a Toast from a background thread on Android?

如何顯示來自線程的Toast消息?

您可以通過從您的線程調用ActivityrunOnUiThread方法來實現:

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

我喜歡在我的活動中有一個名為showToast的方法,我可以從任何地方調用它...

public void showToast(final String toast)
{
    runOnUiThread(() -> Toast.makeText(MyActivity.this, toast, Toast.LENGTH_SHORT).show());
}

然后,我最常從MyActivity在任何像這樣的線程上調用它......

showToast(getString(R.string.MyMessage));

這與其他答案類似,但是針對新的可用 API 進行了更新,並且更加清晰。 此外,不假設您處於活動上下文中。

public class MyService extends AnyContextSubclass {

    public void postToastMessage(final String message) {
        Handler handler = new Handler(Looper.getMainLooper());

        handler.post(new Runnable() {

            @Override
            public void run() {
                Toast.makeText(getContext(), message, Toast.LENGTH_LONG).show();
            }
        });
    }
}

一種幾乎適用於任何地方(包括沒有ActivityView )的方法是將Handler抓取到主線程並顯示 Toast:

public void toast(final Context context, final String text) {
  Handler handler = new Handler(Looper.getMainLooper());
  handler.post(new Runnable() {
    public void run() {
      Toast.makeText(context, text, Toast.LENGTH_LONG).show();
    }
  });
}

這種方法的優點是它適用於任何Context ,包括ServiceApplication

這樣這樣,帶有一個顯示ToastRunnable 即,

Activity activity = // reference to an Activity
// or
View view = // reference to a View

activity.runOnUiThread(new Runnable() {
    @Override
    public void run() {
        showToast(activity);
    }
});
// or
view.post(new Runnable() {
    @Override
    public void run() {
        showToast(view.getContext());
    }
});

private void showToast(Context ctx) {
    Toast.makeText(ctx, "Hi!", Toast.LENGTH_SHORT).show();
}

有時,您必須從另一個Thread向 UI 線程發送消息。 當您無法在 UI 線程上執行網絡/IO 操作時,就會發生這種情況。

下面的示例處理這種情況。

  1. 你有 UI 線程
  2. 您必須啟動 IO 操作,因此您無法在 UI 線程上運行Runnable 因此,將您的RunnableHandlerThread上的處理程序
  3. Runnable獲取結果並將其發送回 UI 線程並顯示Toast消息。

解決方案:

  1. 創建一個HandlerThread並啟動它
  2. HandlerThread使用Looper創建一個處理程序requestHandler
  3. 從主線程使用 Looper 創建一個處理程序: responseHandler並覆蓋handleMessage方法
  4. requestHandlerpost一個Runnable任務
  5. Runnable任務中,在responseHandler上調用sendMessage
  6. 這個sendMessage結果在responseHandler調用handleMessage
  7. Message獲取屬性並進行處理,更新 UI

示例代碼:

    /* Handler thread */

    HandlerThread handlerThread = new HandlerThread("HandlerThread");
    handlerThread.start();
    Handler requestHandler = new Handler(handlerThread.getLooper());

    final Handler responseHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            //txtView.setText((String) msg.obj);
            Toast.makeText(MainActivity.this,
                    "Runnable on HandlerThread is completed and got result:"+(String)msg.obj,
                    Toast.LENGTH_LONG)
                    .show();
        }
    };

    for ( int i=0; i<5; i++) {
        Runnable myRunnable = new Runnable() {
            @Override
            public void run() {
                try {

                    /* Add your business logic here and construct the 
                       Messgae which should be handled in UI thread. For 
                       example sake, just sending a simple Text here*/

                    String text = "" + (++rId);
                    Message msg = new Message();

                    msg.obj = text.toString();
                    responseHandler.sendMessage(msg);
                    System.out.println(text.toString());

                } catch (Exception err) {
                    err.printStackTrace();
                }
            }
        };
        requestHandler.post(myRunnable);
    }

有用的文章:

handlerthreads-and-why-you-should-be-using-them-in-your-android-apps

android-looper-handler-handlerthread-i

  1. 獲取 UI Thread Handler 實例並使用handler.sendMessage();
  2. 調用post()方法handler.post();
  3. runOnUiThread()
  4. view.post()

您可以使用Looper發送Toast消息。 通過此鏈接了解更多詳情。

public void showToastInThread(final Context context,final String str){
    Looper.prepare();
    MessageQueue queue = Looper.myQueue();
    queue.addIdleHandler(new IdleHandler() {
         int mReqCount = 0;

         @Override
         public boolean queueIdle() {
             if (++mReqCount == 2) {
                  Looper.myLooper().quit();
                  return false;
             } else
                  return true;
         }
    });
    Toast.makeText(context, str,Toast.LENGTH_LONG).show();      
    Looper.loop();
}

它在您的線程中被調用。 Context 可能是Activity.getContext()從你必須展示 toast 的Activity獲取。

我根據 mjaggard 回答制定了這種方法:

public static void toastAnywhere(final String text) {
    Handler handler = new Handler(Looper.getMainLooper());
    handler.post(new Runnable() {
        public void run() {
            Toast.makeText(SuperApplication.getInstance().getApplicationContext(), text, 
                    Toast.LENGTH_LONG).show();
        }
    });
}

對我來說效果很好。

帶有 runOnUiThread 的 Kotlin 代碼

runOnUiThread(
        object : Runnable {
            override fun run() {
                Toast.makeText(applicationContext, "Calling from runOnUiThread()", Toast.LENGTH_SHORT)  
            }
        }
)

我遇到了同樣的問題:

E/AndroidRuntime: FATAL EXCEPTION: Thread-4
              Process: com.example.languoguang.welcomeapp, PID: 4724
              java.lang.RuntimeException: Can't toast on a thread that has not called Looper.prepare()
                  at android.widget.Toast$TN.<init>(Toast.java:393)
                  at android.widget.Toast.<init>(Toast.java:117)
                  at android.widget.Toast.makeText(Toast.java:280)
                  at android.widget.Toast.makeText(Toast.java:270)
                  at com.example.languoguang.welcomeapp.MainActivity$1.run(MainActivity.java:51)
                  at java.lang.Thread.run(Thread.java:764)
I/Process: Sending signal. PID: 4724 SIG: 9
Application terminated.

之前:onCreate 函數

Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        Toast.makeText(getBaseContext(), "Thread", Toast.LENGTH_LONG).show();
    }
});
thread.start();

之后:onCreate 函數

runOnUiThread(new Runnable() {
    @Override
    public void run() {
        Toast.makeText(getBaseContext(), "Thread", Toast.LENGTH_LONG).show();
    }
});

有效。

爪哇11:

var handler = new Handler(Looper.getMainLooper);
handler.post(() -> Toast.makeText(your_context, "Hi!", Toast.LENGTH_SHORT).show());

不過,在 Java 8 中可以使用 Lambda。 var是在 Java 11 中引入的。

與此處幾乎所有答案相反, Toast#makeTextToast#show不必在 UI 線程上運行。 唯一的要求是它在一個名為Looper#prepare的線程上運行。

這是因為 toast 是由操作系統處理和呈現的,而不是應用程序。 在內部, Toast#show調用系統服務以將 toast 排隊。

這意味着下面的代碼是有效的

private static class MyThread extends Thread {
    public Handler handler;

    @Override
    public void run() {
        Looper.prepare();

        handler = new Handler(Looper.myLooper()) {
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
            }
        };

        Looper.loop()
    }
}

final private MyThread t = new MyThread();
// start and wait for t to start looping

private void onClick() {
    t.handler.post(() -> Toast.makeText(this, "this works", Toast.LENGTH_SHORT).show());
}

onCreate 中的方法:

private void toastPublic(final String message){
    Handler handler = new Handler(Looper.getMainLooper());
    handler.post(new Runnable() {
       public void run() {
          Toast.makeText(getBaseContext(),""+message, 
             4 /*Toast.LENGTH_SHORT*/).show();
    }});
}

下一步:在線程內部使用

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM