2

ループがあるUIと他のスレッドがあります:

while(true){

}

システム内の文字列値の変更を確認しており、変更された場合は、事前に開いているソケットを介してサーバーにメッセージを送信します。問題は、ループを適用するとアプリがフリーズし、CPU 負荷が非常に高くなる (約 90%) ことです。無限ループはスレッドで実行してはいけませんが、無限ループを使用せずにこの動作をコピーする方法を知っていますか?

どうも

メイン コード (onCreate メソッド):

    mProgressDialog = ProgressDialog.show(main.this, "loading","loading", true);
    c=new Client(this.getApplicationContext(), "192.168.0.121", 3333);
    c.start();

    CLIENT_MESSAGE="login user2 user2";
    synchronized(c){
        c.notify();
    }
    Client.zHandler.setEmptyMessage(119);


    mHandler = new Handler()
    {
        public void handleMessage(android.os.Message msg)
        {
            super.handleMessage(msg);

            switch (msg.what)
            {
                case 11:
                    Log.d("Logged in", "login");
                    mProgressDialog.dismiss();
                    break;
                case 12:    
                    Log.d("Logged out", "logout and end");
                    mProgressDialog.dismiss();
                    finish();
                    break;

                        }
                 }
          };

  @Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    switch (keyCode) {

    case KeyEvent.KEYCODE_BACK:
        CLIENT_MESSAGE="logout";
        synchronized (c) {
            c.notify();
        }
                    Client.zHandler.setEmptyMessage(129)
        break;
    default:

    }
    return true;
}

スレッド コード (Client.java):

public Client(Context ctx, String hostname, int port){
    this.ctx=ctx;
    this.hostname=hostname;
    this.port=port;

    zHandler = new Handler()
    {
        public void handleMessage(android.os.Message msg)
        {
            super.handleMessage(msg);

            switch (msg.what)
            {
                case 119://login
                    Log.d("119", "case 119");
                    messageText=DropboxFileClientActivity.CLIENT_MESSAGE;
                    main.mHandler.sendEmptyMessage(11);
                    break;
                case 129://logout
                    messageText=DropboxFileClientActivity.CLIENT_MESSAGE;
                    main.mHandler.sendEmptyMessage(12);
                    break;
                case 100:   
                    break;

                        }
                 }
          };
}
    public void run(){
      try {
        clientSocket = new Socket(hostname, port);
        //inputLine = new BufferedReader(new InputStreamReader(System.in));

        os = new ObjectOutputStream (clientSocket.getOutputStream());

        is = new ObjectInputStream(clientSocket.getInputStream());
    }
    catch (UnknownHostException e) {
        Log.d("ERROR", "unknown host "+hostname); 
    }
    catch (IOException e) {
        Log.d("ERROR2", "no bind"+hostname);
        e.printStackTrace();
    }

    while (!isInterrupted()) {
        try{
            synchronized (this) {
                wait();
            }
        } catch (InterruptedException e) {
            break; // interrupting the thread ends it
        }
        if (clientSocket != null && os != null && is != null &&!messageText.equals("")) {
                messageText="";
                //sending message to server, getting reply and displaying it to the screen
            } 
      }//endwhile loop

   }
4

2 に答える 2

7

ループが実際に別のスレッドで実行されている場合、問題はそれが CPU を占有していることです。

値の変更をチェックするためにポーリングするよりも、String(関連するコードを制御できる場合) 他のスレッドからサーバーの更新をトリガーするセッターを作成する方がはるかに優れています (たとえば、wait/notifyプロトコルを使用)。

ポーリングする必要があるとしても、本当に CPU 速度でそれを行う必要がありますか? おそらく1秒に1回でしょうか?そうすれば、残りの時間は眠ることができます。

少なくとも、Thread.yield()ループを介して毎回呼び出します。

EDIT投稿へのコメントに基づいて、バックグラウンドスレッドで待機する必要があります:

バックグラウンド スレッドで:

while (!isInterrupted()) {
    synchronized (this) {
        wait();
    } catch (InterruptedException e) {
        break; // interrupting the thread ends it
    }
    // read string and send it to the server
}

イベント ハンドラーで:

public void onSomethingHappened(...) {
    // update the string
    synchronized (mThread) {
        mThread.notify();
    }
}

読み取りと更新が同じオブジェクトで同期されない限り、文字列は volatile とマークする必要があります。

于 2012-11-26T18:27:51.977 に答える
1

やっている

synchronized(blah){
    blah.wait();
}

同期を行う古い方法です。java.util.concurrent パッケージのいくつかのクラスを見てください。

例として、アクティビティでは TextWatcher を実装/追加でき、メソッドではできる

blockingQueue.put(theChangedText) //preferably you would do the put via an access method.

あなたのスレッドでは、おおよそ次のようになります。

obj = blockingQueue.take()
sendToServer(obj)
于 2012-11-27T02:19:23.330 に答える