如何在Handler/线程内显示Toast?

8

一旦消息被发送到套接字,我希望显示一个Toast。在这行代码之后:"Log.d(“ClientActivity”,“C:已发送。”);"

我是否需要创建一个单独的线程来显示Toast?

注:Toast是一种轻量级的信息提示框,用于向用户显示简短的信息。
public class ClientActivity extends Activity {
private Handler handler = new Handler();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.client);
    serverIp = (EditText) findViewById(R.id.EditText01);
    message =(EditText) findViewById(R.id.EditText02);
    connectPhones = (Button) findViewById(R.id.Button01);

}

    public void Click1(View v) {
        if (!connected) {
            serverIpAddress = serverIp.getText().toString();
            if (!serverIpAddress.equals("")) {
                Thread cThread = new Thread(new ClientThread());
                cThread.start();
            }
        }
    }


private class ClientThread implements Runnable {

    public void run() {
        try {
            InetAddress serverAddr = InetAddress.getByName(serverIpAddress);
            Log.d("ClientActivity", "C: Connecting...");
            Socket socket = new Socket(serverAddr, ServerActivity.SERVERPORT);
            connected = true;
            while (connected) {
                try {
                    if(i>5)
                    {


                    } 
                    else
                    {   
                        Log.d("ClientActivity", "C: Sending command.");
                        PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket
                                .getOutputStream())), true);
                        // where you issue the commands
                        message1= message.getText().toString();
                        out.println(message1);
                        i=i+1;
                        Log.d("ClientActivity", "C: Sent.");
                    }    
                } catch (Exception e) {
                    Log.e("ClientActivity", "S: Error", e);
                }
            }
            socket.close();
            Log.d("ClientActivity", "C: Closed.");
        } catch (Exception e) {
            Log.e("ClientActivity", "C: Error", e);
            connected = false;
        }
    }
}

}

4个回答

22

放置

  runOnUiThread(new Runnable() {
                 public void run() {

                     Toast.makeText(ClientActivity.this,"asdf",Toast.LENGTH_LONG).show();
                }
            });

这行代码之后

  Log.d("ClientActivity", "C: Connecting...");

它仍然会抛出一个错误信息:“Toast中的makeText(Context、CharSequence、int)方法对于参数(new Runnable(){},String、int)不适用。” - Shan
1
@Shan,您可能正在传递错误的上下文。请仔细检查您是否传递了正确的上下文,而不仅仅是“this”。 - SoundsDangerous
供以后参考:当从可运行的代码块内调用toast时,一定要写ActivityName.this或显式地指定上下文(例如在活动外部的类中)。仅写“this”会让Android(和Android Studio)认为您正在引用Runnable而不是活动(因此不是上下文)。这与嵌套类相同:调用“this”不是指嵌套类所在的活动;它指的是嵌套类本身,因此不是上下文。Runnable也是如此。 - Zoe stands with Ukraine

3
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
    @Override
    public void run() {
        System.out.println("I'm in handler");
        Toast.makeText(YourActivity.this, "This is a toast", Toast.LENGTH_SHORT).show(); 
    }
}, 1000);             

1
如果上下文是一个Activity(就像你用YourActivity.this暗示的那样),你可以直接使用runOnUiThread(),对吗? - David Doria
@DavidDoria 您是正确的,因为 handler 仅用于执行任何 UI 更改,当您查看 runOnUiThread 方法实现时,它首先检查当前线程是否为 UI 线程,如果当前线程不是 UI 线程,则在 handler 中执行给定任务。 - itechDroid

3

您无法在线程内创建 Toast。因为这个新线程没有访问您传递给它的 getApplicationContext() 的权限。 您需要与 UI 线程(即主线程)建立通信。
因此,每当您想要显示 Toast 时,请使用 handler.Post(Runnable) 方法进行操作。Handler 是 UI 线程和您正在运行的独立线程之间的中间人。所有 UI 操作都必须在 handler.Post(Runnable)run() 方法中完成。

因此,在您的活动中,要显示 Toast,请执行以下操作:

private class ClientThread implements Runnable {

    public void run() {
        try {
            InetAddress serverAddr = InetAddress.getByName(serverIpAddress);
             .....
             .....
              message1= message.getText().toString();
                        out.println(message1);
                        i=i+1;
                        Log.d("ClientActivity", "C: Sent.");
                        handler.post(new Runnable(){
                          public void run()
                          {
                             Toast.make(....);
                           }
                         });

不要忘记在主活动(线程外)中声明和初始化处理程序对象

handler=new Handler();

1
首先声明一个全局的 Handler。
Handler handler=null;

在您的onCreate()中创建一个处理程序,如下所示:
Handler handler=new Handler()
{
  public void handleMessage(Message msg)
{
  if(msg.what==0)
{
   Toast.makeText(ClientActivity.this,"Your Toast Mesage Goes here",Toast.LENGTH_LONG).show();
}

}
};

现在在您的Runnable类中,在"Log.d("ClientActivity", "C: Sent.");"之后添加此行。

handler.sendEmptyMessage(0);

您面临的问题是因为无法从可运行对象更新UI。处理程序将您连接到主UI,因此您必须从可运行对象向处理程序传递消息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接