1

クライアントまたはサーバーが接続を切断するまで、サーバーから受信データを常に読み取るために使用されるTCPクライアントとして使用されるTCPソケットがあります。他の方法はわかりませんが、別の Runnable スレッドでwhile (true)ループを使用し、その中で (while ループで) 着信データをチェックします。受信したデータはEditTextに出力する必要があります。

私が抱えている問題は、Handler.post(...)からテキストを更新することです。

そんなこと知ってる:

  • Android 3.0 以降で TCP 接続を作成するには、Strict モードがデフォルトで有効になっており、無効にしたくないため、TCP コードをnew Thread(...)またはAsyncTaskに配置する必要があります。

  • Android で新しいスレッドから UI を更新するには、 Threadを使用する場合は Handler.post() を使用する必要があり、AsyncTask を使用する場合publichProgressを介してonProgressUpdateを使用する必要があることを知っています。両方で奇妙なイライラする問題が発生しています。

だから、私がやりたいことは次のとおりです。

  • サーバーを永続的にリッスンする
  • サーバーが「w」、「a」、または「n」などのメッセージを送信するとすぐに、すぐにそれを EditText に表示します。あなたはそれをtelnetセッションと考えることができますが、私はすべての単一バイトを処理したいので、telnetよりも「より多くの」精度必要です。一度に 1バイトずつ読み取るか、バイトのバッファーを取得してから、バッファーを反復処理して個別に処理する必要があります一度にバイトで行きました。

これが私が持っているコードです。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

final として定義せずにどのようにアクセスできるNextByteのかわかりません!?public void run()

  • ハンドラーがアクティビティ UI スレッドにメッセージを送信するようにする場合は、アクティビティ クラスに作成して、そのルーパーにアクセスできるようにする必要があります。

次のように、問題の2つの解決策を考えることができます。

1-NextByte値を変数として渡すカスタムRunnableクラスを使用するには

   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 に答える