有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

JavaAndroid:线程可运行和处理程序。在run方法中发布问题(Handler.postXX在预期情况下不会按时运行)

我有一个TCPsocket用作TCP客户端,用于不断地从服务器读取传入数据,直到客户端或服务器断开连接。我不知道还有其他方法,但在不同的可运行线程中使用while(true)循环,并在其中(while循环)检查传入数据。接收到的数据需要打印在编辑文本中

我遇到的问题是从处理程序更新文本。职位(……)

我知道:

  • 为了使用Android 3.0及更高版本创建TCP连接,我需要将TCP代码放在新线程中(…)异步任务,因为默认情况下已启用严格模式,我不想禁用它

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

所以,我想做的就是:

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

这是我的代码,请注意我上面的评论。响应查看我遇到的问题。我希望你能解决这个问题

代码编写得非常简单,我已经删除了本示例的许多错误检查部分

我有一个名为: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的文档。张贴方法,看看我是否有意义

我希望您有一个解决方案,我知道“while(true)”不是一个好的实践,但我可以通过设置标志从线程外部打破循环,我不知道其他任何方法如何做到这一点


共 (2) 个答案

  1. # 1 楼答案

    问题已经解决了

    这就是我做的

    在主要活动中。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=thisonCreate中,然后在ThreadClientInput中。跑步

            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

  2. # 2 楼答案

    我不确定您如何能够从public void run()访问NextByte,而不将其定义为final

    • 如果您希望处理程序将消息发布到活动UI线程,您应该在活动类中创建它,以便它可以访问其循环器

    我可以为您的问题想出以下两种解决方案:

    1-使用自定义可运行类,将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-使用处理程序。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
            }
        };