2015-04-22 3 views
0

Я новичок в разработке Android, но не новичок в Java.Тема заставляет программу сбой

Одно золотое правило - никогда не блокировать нить графического интерфейса, ни главную нить.

Проблема, с которой я столкнулся, заключается в том, что мое приложение может отправлять сообщения на сервер, а сервер отображает сообщения. Когда мой сервер (ПК) отправляет сообщения обратно в мое приложение для Android, приложение получает сообщение, и это видно из-за log method.

Консоль отображает сообщение, отправленное с сервера, но приложение GUI этого не делает, потому что оно зависает.

То, что я сделал, это установить нить, в другую сторону. `Main Thread> Thread (подключается к серверу)> Thread (прослушивает входящие сообщения)> Thread (Android Gui Thread).

Проблема здесь; программа зависает, и действие перестает отвечать. При этом консольное окно отображает сообщения, отправленные с сервера.

Мой вопрос: почему приложение замораживается, когда я не блокирую нити?

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 есть только один поток. Некоторые люди называют его потоком пользовательского интерфейса, но это плохая практика. Просто подумайте о единственном (основном) потоке как об обработке основного кода, а также о том, что нужно сделать с пользовательским интерфейсом. – Squonk

ответ

2

Ну, этот блок:

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

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

запускается на неопределенный срок внутри цикла while, и, следовательно, блокирует основной поток. Зачем вам нужно создать свой displayMessages в основной теме? Думаю, вы можете просто положить displayMessages.append(message +"\n"); в свою петлю while.

+0

Итак, 'Android runOnUIThread' блокирует основной поток? Когда пользователь получает сообщение с сервера, он обновляет 'сообщение' до' TextView'. – Moynul

+0

@Moynul UI нить * есть * основной нить. – AndroidEx

+0

A О, я думал, что основной поток, порожденный потоком пользовательского интерфейса. Это мое плохое. Я просто проверю ваш ответ. – Moynul

1

Если я не ошибаюсь, input.nextLine(); блокирует поток до тех пор, пока сообщение не будет получено с сервера.

Итак, если я прав, когда вы получаете новое сообщение с сервера, вы запускаете основной поток, чтобы изменить текстовое представление, которое у вас есть ... но в runOnUiThread вы снова вызываете input.nextLine();, когда вы уже прочитали его значение (String message = input.nextLine();), перед вызовом runOnUiThread(new Runnable() {....

В основном это означает, что ваш основной поток ожидает нового сообщения с сервера. Вам просто нужно использовать значение, которое у вас уже есть, или, я полагаю, вы также можете играть с hasNextLine().

Смежные вопросы