2011-12-07 23 views
0

您好我對Android開發比較陌生,從來沒有必須在Java中使用多線程(我有更多的使用C的低級線程的經驗)。我也從來沒有嘗試過讓自己的事件偵聽器,所以我想我不確定我的錯誤在這裏,但我懷疑它是在我看不到的抽象層次上。Android上的多線程事件發展在Eclipse中的發展

基本上我只是想做一個TCP客戶端偵聽協議。據我所知,我試圖堅持API風格標準,所以我創建了一個Service TCPClient,它除了處理TCP連接外,並通過IBinder遠程方法調用接口直接發送消息。我相對確定這是行得通的,因爲我可以看到我的服務器上的響應(現在只是迴應響應)。我的理解是,調用遠程方法的forground Activity實際上是將其作爲對其他實例的請求,但數據共享似乎是安全的。

對我來說,複雜的部分是線程,因爲我試圖使用阻塞的讀取從套接字讀取,因爲我不想坐下來一遍又一遍地閱讀浪費處理器的時間。所以我讓我的服務產生了一個線程,但什麼都不做,只能坐在那裏阻塞讀取。然後我試着寫一個事件監聽器和我自己的事件來處理它。因此,正在讀取的線程將調用事件偵聽器來提升事件並將其讀取的內容發送到Activity以更新顯示。

我覺得在更新過程中肯定會有一些問題,因爲註釋掉這部分似乎沒有問題。我會發布一些看起來相關的代碼。對不起,我的詳細程度! (我可能過度使用同步)。

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中遇到的問題是任何GUI修改都必須在EDT(Event Dispatch Thread,或Swing中的主UI線程)上完成。這是必需的,因爲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線程上運行。例如,從UI線程調用Activity#onCreate(Bundle)