2015-04-22 156 views
0

我是Android開發新手,但並不是Java新手。線程導致程序崩潰

一條黃金法則是永遠不會阻塞GUI線程,也不會阻塞主線程。

我面臨的問題是我的應用程序可以將消息發送到服務器,並且服務器顯示消息。當我的服務器(PC)將消息發送回我的android應用程序時,應用程序會收到消息,這很明顯是由於log method

控制檯,顯示從服務器發送的消息,但GUI應用程序沒有,這是因爲它凍結。

我所做的是設置一個線程,在另一個線程中。 `主線程>線程(連接到服務器)>線程(偵聽傳入消息)>線程(Android Gui線程)。

這裏的問題是;程序凍結並且活動停止響應。但控制檯窗口確實顯示從服務器發送的消息。

我的問題是,當我沒有阻止任何線程時,爲什麼應用程序被凍結?

private void ConnectButtonPress() { 
    btnConnect.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      btnConnect.setVisibility(View.GONE); 
      btnDisconnect.setVisibility(View.VISIBLE); 
      btnSend.setEnabled(true); 
      enterET.setEnabled(true); 
      new Thread(new Runnable() { 
       public void run(){ 
        try { 
         socket = new Socket(IPAddressET.getText().toString(), Integer.parseInt(portET.getText().toString())); //connect to server 
         input = new Scanner(socket.getInputStream()); 

         pw = new PrintWriter(socket.getOutputStream(), true); 
         pw.println(usersName); //write the message to output stream 
         pw.flush(); 

         new Thread(new Runnable() { 
          @Override 
          public void run() { 
           while (true){//this is where the problem is 
            try { 
             input = new Scanner(socket.getInputStream()); 
            } catch (IOException e) { 
             e.printStackTrace(); 
            } 

            String message = input.nextLine(); 
            Log.i("LOL",message); 
            runOnUiThread(new Runnable() { 
             @Override 
             public void run() { 
              String message = input.nextLine(); 

              displayMessages.append(message +"\n"); 
             } 
            }); 
           } 
          } 
         }).start(); 



         //pw.close(); 
         //pw.close(); //closing the connection 
        } catch (UnknownHostException e) { 
         e.printStackTrace(); 
        } catch (IOException e) { 
         e.printStackTrace(); 
        } 
       } 
      }).start(); 




     } 
    }); 
} 
+0

默認情況下,在Android應用程序中只有一個線程。有些人稱它爲UI線程,但這是一個不好的做法。只需將單一(主)線程想象爲處理主代碼執行以及任何需要使用UI執行的任務。 – Squonk

回答

2

那麼,該塊:

runOnUiThread(new Runnable() { 
@Override 
public void run() { 
    String message = input.nextLine(); 

    displayMessages.append(message +"\n"); 
} 
}); 

while循環內持續運作,因此塊主線程。爲什麼你需要在主線程中建立你的displayMessages?我想你可以在while循環內放置displayMessages.append(message +"\n");

+0

所以'Android runOnUIThread'阻止主線程?當用戶從服務器獲取消息時,它將'message'更新爲'TextView'。 – Moynul

+0

@Moynul UI線程*是主線程。 – AndroidEx

+0

哦,我認爲主線程產生了一個UI線程。這是我的不好。我只會測試你的答案。 – Moynul

1

如果我沒有錯,input.nextLine();會阻塞該線程,直到收到來自服務器的消息。

所以,如果我是正確的,當你從服務器收到一條新消息時,你在主線程上運行以更改文本視圖,但是在runOnUiThread中再次調用input.nextLine();,已經在runOnUiThread(new Runnable() {...呼叫之前讀取了其值(String message = input.nextLine();)。

這基本上會導致您的主線程等待來自服務器的新消息。你只需要使用你已有的價值,或者,我想你也可以玩hasNextLine()