Обновление UI / runOnUiThread / конечных переменных: как написать бережливый код, который обновляет пользовательский интерфейс при вызове из другого потока

#android #user-interface #final

#Android #пользовательский интерфейс #Финал

Вопрос:

Я читал об обновлении пользовательского интерфейса, когда узнал, что, как и WinForms, Android необходимо обновлять пользовательский интерфейс из основного потока (жаль, я надеялся, что кто-нибудь сможет раз и навсегда решить эту раздражающую проблему).

В любом случае, мне нужно передать это в поток пользовательского интерфейса. Некоторые предлагают использовать метод runOnUiThread, и это могло бы сработать, если бы не этот раздражающий «финал», который затем вступил в игру.

У меня есть интерфейс с методом, который я не могу изменить. Это выглядит так:

 @Override
public void connStateChange(ClientHandler clientHandler)
  

Этот метод вызывается, когда я получаю изменение состояния соединения (сеть). Когда я это делаю, мне нужно кое-что сделать, и в данном случае это добавление некоторого текста в TextView.

Итак, я попробовал это, но, конечно, переменная «ClientHandler» не является окончательной:

 @Override
public void connStateChange(ClientHandler clientHandler) {

   runOnUiThread(new Runnable()
   {
      public void run()
      {
        tv.append(clientHandler.getIP()   ", "   clientHandler.state.toString()   "n");
        if (clientHandler.state == State.Connected)
        {
            tv.append("Loginserver hittad");
        }
      }
   });
}
  

Как мне красиво, чисто и эффективно написать код в этом примере для обновления пользовательского интерфейса? Мне нужен доступ ко всем моим переменным и т. Д…

Ответ №1:

Попробуйте:

 @Override 
public void connStateChange(ClientHandler clientHandler) {
    final ClientHandler temporaryHander = clientHandler;
    runOnUiThread(new Runnable() {
         public void run() {
               tv.append(temporaryHandler.getIP()   ", "   temporaryHandler.state.toString()   "n"); 
               if (temporaryHandler.state == State.Connected) {
                    tv.append("Loginserver hittad");         
               }       
         }    
    }); 
} 
  

Кстати, код становится более читаемым, если вы объявляете не анонимный класс прямо в методе, а объявляете внутренний класс из методов. Рассматривайте это как команду шаблона.

Пример более чистого и повторно используемого кода.

 @Override 
public void connStateChange(ClientHandler clientHandler) {
    final ClientHandler temporaryHander = clientHandler;
    runOnUiThread(new MyRunnableCommand(temporaryHandler)); 
} 

private class MyRunnableCommand implements Runnable { 

     private ClientHandler clientHandler;

     public MyRunnableCommand(ClientHandler clientHandler) {
         this.clientHandler = clientHandler;
     }

     @Override
     public void run() {
               tv.append(clientHandler.getIP()   ", "   clientHandler.state.toString()   "n"); 
               if (clientHandler.state == State.Connected) {
                    tv.append("Loginserver hittad");         
               }       
         } 

}
  

Хотя сама запускаемая реализация была немного раздута, код стал более удобным для повторного использования и простым для чтения.

Комментарии:

1. Я действительно чувствую, что классы anon непосредственно в методах намного понятнее, чем все остальное, с чем я сталкивался. Однако я не уверен, что такое шаблон команды, поэтому я изучу его.

2. Как пожелаете. Что касается меня, я склонен писать повторно используемый и спартанский код. Классы Inner-in-class более гибкие, чем классы inner-in-methods . Кроме того, метод становится более компактным.

3. Можете ли вы сослаться на какой-нибудь понятный пример, чтобы я понял разницу? Потому что я не думаю, что я =)

4. Извините, нет ссылок 🙂 Я перепишу ответ.