2011-12-07 4 views
0

こんにちは私はAndroid開発には比較的新しいので、Javaでマルチスレッドを使用する必要はありませんでした(私はCでより低レベルのスレッド化の経験があります)。私は自分のイベントリスナーを作る前に決して試みたことがないので、私のエラーがここにあるのかどうかは分かりませんが、見えない抽象レベルのものと思われます。EclipseでのAndroid開発でのマルチスレッドイベントに関する問題

私は基本的にTCPクライアントのリスニングプロトコルを作成しようとしています。私はAPIスタイル標準に固執しようとしています。私はそれらを理解しているので、TCP接続を処理し、IBinderのリモートメソッドコールインターフェイスから直接メッセージを送信するService TCPClientを作成しました。私は私のサーバ上で応答を見ることができるので、これが動作していることは比較的確信しています。私が理解しているのは、リモートメソッドを呼び出すforgroundアクティビティが、実際には他のインスタンスへのリクエストとして作成していますが、データ共有は安全であるようです。

プロセッサの時間を浪費しながら繰り返し読み書きしたくないため、私はブロックされた読み込みをソケットから読み込もうとしていたので、私のための複雑な部分はスレッドです。だから、私のサービスでは何もしないで、そこに座って読み込みをブロックするためのスレッドを生成させます。それから、私はそれを処理するためにイベントリスナーと自分自身のイベントを書きました。したがって、読み込み中のスレッドは、イベントリスナーを呼び出してイベントを発生させ、読み込んだ内容をアクティビティに送り、ディスプレイを更新します。

この部分をコメントアウトするときに問題はないようですので、更新方法に問題があるように感じます。私は関連性のあるコードの部分を投稿します。申し訳ありませんが私の冗談を! (私はおそらく以上の同期を使用)。

public class BossActivity extends Activity 
implements NetworkListener{ 
private static TextView responses; 

private boolean connected = false; 
private TCPClient clientService; 
private ServiceConnection tcpConnection = new ServiceConnection() { 
    public void onServiceConnected(ComponentName className, IBinder service) { 
     clientService = ((TCPClient.LocalBinder)service).getService(); 
     connected = true; 

    } 
    public void onServiceDisconnected(ComponentName className) { 
     clientService = null; 
     connected = false; 
    } 
}; 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.bossactivity);   
//... 
    bindService(new Intent(this, TCPClient.class), 
      tcpConnection, Context.BIND_AUTO_CREATE); 
//.. 
} 

    public void onDataRead(Data d) { 
    clientService.send(d.str); 
    if(null != d && null != d.str) 
     responses.setText(d.str); ///PROBLEM LINE when comment out it        
               ///doesn't die 
} 
}//End BossActivity 


public class TCPClient extends Service{ 
private final LocalBinder mbinder = new LocalBinder(); 

public class LocalBinder extends Binder{ 
    TCPClient getService(){ 
     return TCPClient.this; 
    } 
} 
private NetworkListener networkListener = null; 
public void setOnDataRead(NetworkListener listener){ 
    networkListener = listener; 
} 

public synchronized void dataRead(Data data){ 
    if(null != networkListener && null != data){ 
     networkListener.onDataRead(data); 
    } 
} 
    public IBinder onBind(Intent intent) { 
    return mbinder; 
} 
    public interface NetworkListener extends EventListener { 
    public void onDataRead(Data d); 
} 

public class NetworkReadEvent extends EventObject { 
    private static final long serialVersionUID = -7218678248204219511L; 
    public NetworkReadEvent(Object source) { 
     super(source); 
    } 
} 

public static class Data { 
    String str; 
} 
}//End TCPClient 


public class SocketReader extends Thread { 
    BufferedReader in; 
boolean alive = true; 
boolean updated = false; 
Data data; 
TCPClient parent; 
public SocketReader(BufferedReader input, TCPClient p){ 
     //... 
    } 

     public void run() { 
    String str; 

    while(running()){ 
     try { 
      str = in.readLine(); 
        Data dataBuf = new Data(); 
        dataBuf.str = str; 
          parent.dataRead(dataBuf);   
        } catch (IOException e) { 
      continue; 
     } 
    } 
} 

私は、私がサービスを宣言除くマニフェストで特別何もしませんでしたうち残っているかもしれ何かを明確にすることができます。

ありがとうございます!!!

答えて

0

ほとんどの人がJavaで遭遇する問題は、EDT(Event Dispatch ThreadまたはSwingのメインUIスレッド)でGUIを変更する必要があるということです。 Swingの実装はスレッドセーフではないため、これは必須です。このように、他のスレッドでも動作するUIプログラマは、EventQueue#invokeLater(Runnable)メソッドを自由に使用します。

これとAndroidの対応は、Activity#runOnUiThread(Runnable)のようです。だから、あなたはあなたのコードを変更する必要があります。

@Override 
public void onDataRead(Data d) { 
    clientService.send(d.str); 
    if(null != d && null != d.str) 
    final String dataString = d.str; // Must be final for Runnable to access. 
    runOnUiThread(new Runnable() { 
     @Override 
     public void run() { 
     responses.setText(dataString); 
     } 
    }); 
} 

をあなたはこのことを心配する必要はありません。理由は、通常、あなたは、Androidで上書きするほとんどのメソッドが既にUIスレッド上で実行することです。たとえば、Activity#onCreate(Bundle)がUIスレッドから呼び出されます。