1

我有一个用作 TCP 客户端的 TCP 套接字,用于不断地从服务器读取传入数据——直到客户端或服务器断开连接。我不知道任何其他方式,但在不同的 Runnable 线程中使用while (true)循环并在其中(在 while 循环中)检查传入数据。接收到的数据需要打印在EditText中。

我遇到的问题是从Handler.post(...)更新文本。

我知道:

  • 为了创建与 Android 3.0 及更高版本的 TCP 连接,我需要将 TCP 代码放在新的 Thread(...)AsyncTask中,因为默认情况下已启用严格模式,我不想禁用它。

  • 我知道为了从 Android 中的新线程更新 UI,如果我使用线程,我需要使用 Handler.post();如果使用AsyncTask ,我需要通过publichProgress使用onProgressUpdate,我知道如何使用所有这些,但我是他们俩都遇到了奇怪的令人沮丧的问题。

所以,我想做的就是:

  • 永久收听服务器
  • 一旦服务器向我发送消息,例如:'w' 或 'a' 或 n',我立即将其显示在 EditText 上。您可以将其视为 telnet 会话,但我需要比 telnet“更高”的精度,因为我想处理每个字节,甚至是不可打印的字节,所以无论如何我都不想使用readLine。我必须一次读取一个字节或获取一个字节缓冲区,然后通过遍历缓冲区来分别处理它们。我一次只带一个字节。

这是我的代码,请注意我在 handle.response 上面的评论,看看我遇到的问题。我希望你能清除这个。

该代码的编码非常简短,我已经删除了该示例的许多错误检查部分。

我有一个名为:ThreadClientInput 的新类:

public class ThreadClientInput  implements Runnable {

InputStream inputStream;
MainActivity mainActivity;
Handler handler = new Handler();
int NextByte = 0;

public ThreadClientInput(MainActivity ma)
{
    mainActivity = ma;
}

@Override
public void run() 
{ 
    ////////////////////////////////////////////////////////////////
    // Run the sensitive code that requires us to create this thread
    try {
        mainActivity.tcp_Client = new Socket("192.168.1.90", 23);
    }
    catch (Exception e){Log.e("EXEPTION:", e.getMessage().toString());return;}
    ////////////////////////////////////////////////////////////////


    // Only try to get the inputStream if we have a successful connection
    if (mainActivity.tcp_Client != null) 
    {
        try 
        {
            inputStream = mainActivity.tcp_Client.getInputStream();
        }
        catch (Exception e){Log.e("EXEPTION:", e.getMessage().toString()); return;}
    }


    /////////////////////////////////////////////
    /////////////////////////////////////////////
    // Update the text on the "Connect" button
    handler.post(new Runnable() 
    {
        @Override
        public void run() 
        { mainActivity.btn_Connect.setText("Connected");}
    });
    /////////////////////////////////////////////
    /////////////////////////////////////////////

    try 
    {   

        // I need to constantly read the data until we manually disconnect or
        // the server drops the connection
        while (true) 
        {
            // Get the next byte
            // I do not want to use "readline()" from a BufferedReader etc because I need to know exactly what's coming in
            // I need to process every single byte
            NextByte = inputStream.read();

            if (NextByte > -1)
            {
                Log.e("in (While loop):", Character.toString((char)NextByte));

                *** Here is the problem ****
                // Update the EditText and this is where the problem starts
                // if the server sends "1234", the Log.e() above will display everything correctly: "1234"
                // however the handler.post below will run at the end of the last byte so the
                // the EditText as well as the second Log.e below within the handle.post will display: "1444" or "4444" or "2444"
                // So the handler.post does *not* run immediately even if I try handle.postAtFrontOfQueue()
                // If the server sends "12345678", again, Log.e() above will display everything correctly: "12345678" 
                // however the handler.post below will run at the end of the last byte again
                // and I will get "88888888" (most of the time) or "18888888" 

                //   

                handler.post(new Runnable() 
                {
                    @Override
                    public void run() 
                    {
                        mainActivity.et_Response.setText(mainActivity.et_Response.getText() + Character.toString((char)NextByte));
                        Log.e("In handler.post:", Character.toString((char)NextByte));
                    }
                });
            }
        }           
    }
    catch (Exception e){Log.e("EXEPTION:", e.getMessage().toString());}
}}

我尝试了各种变体,包括一种带有runOnUiThread和 AsyncTask 的变体,但我得到了相同的结果。我出去了,我什么都没有。目前我只是在阅读一些关于 Handle.post 方法的文档,看看我是否有意义。

我希望你有一个解决方案,我知道“ while (true) ”不是一个好习惯,但我可以通过设置一个标志从线程外部打破循环,我不知道如何做到这一点.

4

2 回答 2

1

我不确定您如何在NextBytepublic void run()将其定义为 final 的情况下进行访问!?

  • 如果您希望处理程序将消息发布到 Activity UI 线程,您应该Activity 类中创建它,以便它可以访问其 Looper。

我可以为您的问题想到两种解决方案,如下所示:

1-使用自定义 Runnable 类,在其中将 NextByte 值作为变量传递给它,例如

   handler.post(new MyRunnable(NextByte));

MyRunnable 可以是这样的:

  class MyRunnable implements Runnable{
   int byteData;  
   public MyRunnable(int byteData){
      this.byteData = byteData;
   }

     public void run(){ // update the EditText}
  }                          

2- 使用 handler.sendMessage(); 并将 NextByte 添加为消息参数,例如

 Message msg = new Message();
 msg.arg1 = NextBye
 handler.sendMessage(msg);

您的处理程序应定义如下:

handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            int nextByte = msg.arg1;
                            // update the EditText
        }
    };
于 2012-12-29T05:16:11.933 回答
0

问题已解决。

这就是我所做的。

在 MainActivity.java 中,这是主文件,在 MainActivity 类中

    public static class MyRunnable implements Runnable {
    int currentByte = 0;

    public MyRunnable(int b){
        currentByte = b;
    }

    @Override
    public void run() 
    {
        mainActivity.et_Response.setText(mainActivity.et_Response.getText() + Character.toString((char)currentByte));
    }
}

我有一个声明mainActivity = this; onCreate然后在ThreadClientInput.run

        try {
        while (true)
        {
            NextByte = inputStream.read(); 

            // if the server drops the connection, break out the loop
            if (NextByte < 0) break;

            handler.post(new MainActivity.MyRunnable(NextByte));
        }
    }
    catch (Exception e) {
        Log.e("EXCEPTION", e.getMessage());
    }

在此之后,handler.post 会在正确和预期的时间被正确调用。完全归功于 iTech。

于 2012-12-30T05:05:40.040 回答