如何在 Android 上从后台线程显示 Toast?

问题描述 投票:0回答:14

如何显示来自线程的 Toast 消息?

android multithreading android-toast
14个回答
261
投票

您可以通过从线程中调用

Activity
runOnUiThread
方法来完成此操作:

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

72
投票

我喜欢在我的活动中有一个名为

showToast
的方法,我可以从任何地方调用它......

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

然后我最常在像这样的任何线程上从

MyActivity
内部调用它......

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

34
投票

这与其他答案类似,但是针对新的可用 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();
            }
        });
    }
}

26
投票

几乎可以在任何地方(包括没有

Activity
View
的地方)使用一种方法,就是在主线程中获取
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
,包括
Service
Application


10
投票

thisthis,带有显示

Runnable
Toast
。 即,

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

6
投票

有时,您必须从另一个

Thread
向 UI 线程发送消息。当您无法在 UI 线程上执行网络/IO 操作时,就会出现这种情况。

下面的示例处理该场景。

  1. 你有 UI 线程
  2. 您必须启动 IO 操作,因此无法在 UI 线程上运行
    Runnable
    。因此,请将您的
    Runnable
    发布到
    HandlerThread
  3. 上的处理程序
  4. Runnable
    获取结果并将其发送回 UI 线程并显示
    Toast
    消息。

解决方案:

  1. 创建一个HandlerThread并启动它
  2. 使用HandlerThread中的Looper创建
    Handler
    requestHandler
  3. 从主线程创建带有 Looper 的处理程序:
    responseHandler
    并覆盖
    handleMessage
    方法
  4. post
    Runnable
     上的 
    requestHandler
  5. 任务
  6. Runnable
    任务中,调用
    sendMessage
     上的 
    responseHandler
  7. sendMessage
    结果在
    handleMessage
    中调用
    responseHandler
  8. 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);
    }

有用的文章:

处理线程以及为什么你应该在你的 Android 应用程序中使用它们

android-looper-handler-handlerthread-i


5
投票
  1. 获取 UI Thread Handler 实例并使用
    handler.sendMessage();
  2. 调用
    post()
    方法
    handler.post();
  3. runOnUiThread()
  4. view.post()

3
投票

您可以使用

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

它在你的线程中被调用。上下文可能是

Activity.getContext()
Activity
获取,您必须展示吐司。


2
投票

我根据 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();
        }
    });
}

对我来说效果很好。


2
投票

带有 runOnUiThread 的 Kotlin 代码

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

0
投票

java 11:

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

Lambda 在 java 8 中可用。

var
是在java 11中引入的。


0
投票

与这里几乎所有答案相反,

Toast#makeText
Toast#show
确实NOT必须在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());
}

0
投票

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

下一步:在线程内部使用


0
投票

我遇到了同样的问题:

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

成功了。

© www.soinside.com 2019 - 2024. All rights reserved.