Урок 85. Еще несколько способов выполнения кода в UI-потоке

Обсуждение уроков
Аватара пользователя
damager82
Администратор
Сообщения: 1383
Зарегистрирован: 07 янв 2012, 11:32
Контактная информация:

Урок 85. Еще несколько способов выполнения кода в UI-потоке

Сообщение damager82 » 06 июн 2012, 23:00

В этом уроке:
- рассмотрим еще пару способов запуска Runnable в UI-потоке 


Click here to read this article!
Последний раз редактировалось damager82 20 май 2017, 20:08, всего редактировалось 5 раз.
Добро пожаловать на форум сайта StartAndroid
ИзображениеИзображение

Аватара пользователя
KamiSempai
Сообщения: 1339
Зарегистрирован: 17 фев 2012, 21:23
Откуда: Мордор

Re: Урок 85. Еще несколько способов выполнения кода в UI-пот

Сообщение KamiSempai » 07 июн 2012, 17:52

Первые два похожи и отправляют Runnable на немедленную обработку. Я не знаю в чем их принципиальное отличие. Если у вас есть соображения на этот счет, пишите на форуме в ветке этого урока.
Привожу исходный код:

Код: Выделить всё

    private final Handler mHandler = new Handler();

    public final void runOnUiThread(Runnable action) {
        if (Thread.currentThread() != mUiThread) {
            mHandler.post(action);
        } else {
            action.run();
        }
    }
В общем ни чего сложного. Если мы не в своем потоке используем заранее созданный Handler (кстати, ето единственное место, где он используется :D), если в своем потоке, в лоб запускаем run.

С View на много сложнее:

Код: Выделить всё

    public boolean post(Runnable action) {
        Handler handler;
        if (mAttachInfo != null) {
            handler = mAttachInfo.mHandler;
        } else {
            // Assume that post will succeed later
            ViewRoot.getRunQueue().post(action);
            return true;
        }
        return handler.post(action);
    }
Я так понимаю, mAttachInfo - это интерфейс, который создается в момент расположения View на экране, причем создается не в View а передается в качестве параметра.
В случае с ViewRoot все еще более запутано. Времени нет разбираться, на тренировку пора :)

PS: View.postDelayed(Runnable, long) аналогичен View.post(Runnable, long).
R.id.team
Хватит таскать макулатуру на тренировку! Используй T Note.

Аватара пользователя
damager82
Администратор
Сообщения: 1383
Зарегистрирован: 07 янв 2012, 11:32
Контактная информация:

Re: Урок 85. Еще несколько способов выполнения кода в UI-пот

Сообщение damager82 » 08 июн 2012, 09:22

Код я тоже смотрел.
Я имею ввиду разницу с точки зрения использования двух этих методов для разраба. Как решить, какой юзать. И в чем разница по функционалу.
Добро пожаловать на форум сайта StartAndroid
ИзображениеИзображение

Аватара пользователя
KamiSempai
Сообщения: 1339
Зарегистрирован: 17 фев 2012, 21:23
Откуда: Мордор

Re: Урок 85. Еще несколько способов выполнения кода в UI-пот

Сообщение KamiSempai » 08 июн 2012, 18:01

Если брать пример из урока, разницы, на мой взгляд, никакой. Все Runnable смирно встают в очередь и ждут когда впереди стоящие сообщения отработают.
Однако, если взять View не расположенную на форме (например, создать: v = new View(this)), Runnable выполнен не будет. По крайней мере у меня он не выполнился.
Видимо ViewRoot не очень хорошо справляется с этой задачей. Следовательно, если есть шанс наткнуться на View не расположенную на экране лучше использовать runOnUiThread().

Недостаток runOnUiThread() - нет возможности запускать Runnable с задержкой. Но если подумать, кому, кроме как извращенцу, понадобится обновлять экранные компоненты с задержкой? :)
Еще одна особенность runOnUiThread(), если вызвать его в UI потоке, Runnable выполнится тут-же, не вставая в очередь.
Например, мы вызываем runOnUiThread(runn1), за ним сразу tvInfo.post(runn2), но внутри runn1 у нас runOnUiThread(runn3). Порядок выполнения будет: runn1, runn3, runn2.
В случае с tvInfo.post(runn3) такой перестановки не произойдет.

Вывод который я лично для себя сделал: По возможности стараться использовать runOnUiThread(), так как задача будет выполнена 100%. Если нет доступа к Activity, например в другом классе, но есть ссылка на View, которую нужно изменить, можно смело использовать View.post().

UPD [09.06.2012]: Беру свои слова, про извращенцев и обновление UI с задержкой, обратно.
Погорячился немного. Или я сам из этих? :D
R.id.team
Хватит таскать макулатуру на тренировку! Используй T Note.

Jane
Сообщения: 6
Зарегистрирован: 11 июл 2012, 12:30

Re: Урок 85. Еще несколько способов выполнения кода в UI-пот

Сообщение Jane » 15 июл 2012, 11:56

Не совсем поняла.
Ui-поток - это наш основной поток. В нём мы создаём Handler, следовательно, этот Handler привязан к основному потоку. А из другого потока мы передаём в ui-поток через Handler сообщения.
Если не использовать Handler, а три метода из этого урока, то мы опять же влияем на основной поток, но только без Handler.
Да?

Аватара пользователя
damager82
Администратор
Сообщения: 1383
Зарегистрирован: 07 янв 2012, 11:32
Контактная информация:

Re: Урок 85. Еще несколько способов выполнения кода в UI-пот

Сообщение damager82 » 17 июл 2012, 10:59

Jane писал(а):Не совсем поняла.
Ui-поток - это наш основной поток. В нём мы создаём Handler, следовательно, этот Handler привязан к основному потоку. А из другого потока мы передаём в ui-поток через Handler сообщения.
Если не использовать Handler, а три метода из этого урока, то мы опять же влияем на основной поток, но только без Handler.
Да?
Просто здесь реализация Handler скрыта внутри этих методов и нам не надо думать об этом. Но механизм тот же.
Добро пожаловать на форум сайта StartAndroid
ИзображениеИзображение

Artemko
Сообщения: 26
Зарегистрирован: 16 июл 2012, 15:09

Re: Урок 85. Еще несколько способов выполнения кода в UI-пот

Сообщение Artemko » 29 авг 2012, 10:30

а как выполнять этот кусок кода например каждую минуту?

Код: Выделить всё

Thread t = new Thread(new Runnable() {
            public void run() {
              try {
                TimeUnit.SECONDS.sleep(2);
                runOnUiThread(runn1);
                TimeUnit.SECONDS.sleep(1);
                tvInfo.postDelayed(runn3, 2000);
                tvInfo.post(runn2);
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
            }
          });
          t.start();

Аватара пользователя
rezak90
Сообщения: 3422
Зарегистрирован: 26 июн 2012, 13:22
Откуда: UA
Контактная информация:

Re: Урок 85. Еще несколько способов выполнения кода в UI-пот

Сообщение rezak90 » 29 авг 2012, 10:31

Artemko писал(а):а как выполнять этот кусок кода например каждую минуту?

Код: Выделить всё

Thread t = new Thread(new Runnable() {
            public void run() {
              try {
                TimeUnit.SECONDS.sleep(2);
                runOnUiThread(runn1);
                TimeUnit.SECONDS.sleep(1);
                tvInfo.postDelayed(runn3, 2000);
                tvInfo.post(runn2);
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
            }
          });
          t.start();
http://developer.android.com/intl/ru/re ... rTask.html
R.id.team
Политика на форуме запрещена

Artemko
Сообщения: 26
Зарегистрирован: 16 июл 2012, 15:09

Re: Урок 85. Еще несколько способов выполнения кода в UI-пот

Сообщение Artemko » 29 авг 2012, 10:43

так будет правильно?

Код: Выделить всё

myTimer.schedule(new TimerTask() {
			@Override
			public void run() {
				t.start();
			}         	
        }, 0L, 60L * 1000); 
        
        Thread t = new Thread(new Runnable() {
            public void run() {
              try {
                TimeUnit.SECONDS.sleep(2);
                runOnUiThread(runn1);
                TimeUnit.SECONDS.sleep(1);
                tvInfo.postDelayed(runn3, 2000);
                tvInfo.post(runn2);
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
            }
          });

Аватара пользователя
rezak90
Сообщения: 3422
Зарегистрирован: 26 июн 2012, 13:22
Откуда: UA
Контактная информация:

Re: Урок 85. Еще несколько способов выполнения кода в UI-пот

Сообщение rezak90 » 29 авг 2012, 10:47

run() в TimerTask'e это уже отдельный поток, зачем в отдельном потоке городить ещё один поток)))
R.id.team
Политика на форуме запрещена

Artemko
Сообщения: 26
Зарегистрирован: 16 июл 2012, 15:09

Re: Урок 85. Еще несколько способов выполнения кода в UI-пот

Сообщение Artemko » 29 авг 2012, 10:56

а как сделать нормально?
у меня всё подчеркивает красным если я удаляю run()

Аватара пользователя
neoksi
Сообщения: 712
Зарегистрирован: 26 июл 2012, 10:42
Контактная информация:

Re: Урок 85. Еще несколько способов выполнения кода в UI-пот

Сообщение neoksi » 29 авг 2012, 11:03

Код: Выделить всё

myTimer.schedule(new TimerTask() {
			@Override
			public void run() {
	try {
                TimeUnit.SECONDS.sleep(2);
                runOnUiThread(runn1);
                TimeUnit.SECONDS.sleep(1);
                tvInfo.postDelayed(runn3, 2000);
                tvInfo.post(runn2);
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
			}         	
        }, 0L, 60L * 1000); 
        


d.u.a.l
Сообщения: 2
Зарегистрирован: 14 мар 2015, 19:56

Re: Урок 85. Еще несколько способов выполнения кода в UI-пот

Сообщение d.u.a.l » 14 мар 2015, 20:00

А почему в уроке №80 код

Код: Выделить всё

public void onclick(View v) {
    switch (v.getId()) {
    case R.id.btnStart:
      Thread t = new Thread(new Runnable() {
        public void run() {
          for (int i = 1; i <= 10; i++) {
            // долгий процесс
            downloadFile();
            // обновляем TextView
           tvInfo.setText("Закачано файлов: " + i);
            // пишем лог
            Log.d(LOG_TAG, "i = " + i);
          }
        }
      });
      t.start();
      break;
    case R.id.btnTest:
      Log.d(LOG_TAG, "test");
      break;
    default:
      break;
    }
  }
в результате обращения из другого потока ко View-элементу вызывал ошибку Only the original thread that created a view hierarchy can touch its views.
А код, который тоже обращается к аналогичному View (TextView) из другого потока в данном уроке

Код: Выделить всё

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    tvInfo = (TextView) findViewById(R.id.tvInfo);

    Thread t = new Thread(new Runnable() {
      public void run() {
        try {
          TimeUnit.SECONDS.sleep(2);
          runOnUiThread(runn1);
          TimeUnit.SECONDS.sleep(1);
          tvInfo.postDelayed(runn3, 2000);
          tvInfo.post(runn2);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    });
    t.start();
  }
работает???

K_Vladimir
Сообщения: 36
Зарегистрирован: 28 июн 2015, 03:13

Re: Урок 85. Еще несколько способов выполнения кода в UI-пот

Сообщение K_Vladimir » 27 июл 2015, 11:06

Всем доброго дня!
Выходит что НЕЛЬЗЯ вызывать runOnUiThread(runn1); в основном потоке.
Я попробовал убрать создание нового потока и вызвать все наши испытуемые методы из основного потока.
В результате на экране отобразился только runn2 и runn3. Т.е. runOnUiThread(runn1); не сработал.

Код: Выделить всё

 try {
            TimeUnit.SECONDS.sleep(2);
            runOnUiThread(runn1);
            TimeUnit.SECONDS.sleep(1);
            tvInfo.postDelayed(runn3, 2000);
            tvInfo.post(runn2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

rePlay
Сообщения: 7
Зарегистрирован: 11 июл 2015, 17:54

Re: Урок 85. Еще несколько способов выполнения кода в UI-пот

Сообщение rePlay » 28 июл 2015, 18:05

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

K_Vladimir
Сообщения: 36
Зарегистрирован: 28 июн 2015, 03:13

Re: Урок 85. Еще несколько способов выполнения кода в UI-пот

Сообщение K_Vladimir » 29 июл 2015, 01:08

rePlay писал(а):K_Vladimir Можно, просто ты нагрузил UI-поток, и поэтому экран не обновляется. Экран начнёт обновляться после отработки метода OnCreate (предполагаю, что в нем тестировал код).
Попробовал вынести из onCreate. Через кнопку, срабатывают только runn2 и runn3.
Я думаю что вызывать этот метод из основного потока просто нет никакого смысла

rePlay
Сообщения: 7
Зарегистрирован: 11 июл 2015, 17:54

Re: Урок 85. Еще несколько способов выполнения кода в UI-пот

Сообщение rePlay » 29 июл 2015, 03:29

K_Vladimir писал(а):
rePlay писал(а):K_Vladimir Можно, просто ты нагрузил UI-поток, и поэтому экран не обновляется. Экран начнёт обновляться после отработки метода OnCreate (предполагаю, что в нем тестировал код).
Попробовал вынести из onCreate. Через кнопку, срабатывают только runn2 и runn3.
Я думаю что вызывать этот метод из основного потока просто нет никакого смысла
Неправильный вывод. Я же говорю, что ты загрузил UI-поток всякими sleep'ами, из-за чего он не обновляется. Закомментируй
tvInfo.post(runn2); и появится run1. Нужно просто понимать, как отрабатывает твое приложение.

K_Vladimir
Сообщения: 36
Зарегистрирован: 28 июн 2015, 03:13

Re: Урок 85. Еще несколько способов выполнения кода в UI-пот

Сообщение K_Vladimir » 29 июл 2015, 10:53

rePlay писал(а):
K_Vladimir писал(а):
rePlay писал(а):K_Vladimir Можно, просто ты нагрузил UI-поток, и поэтому экран не обновляется. Экран начнёт обновляться после отработки метода OnCreate (предполагаю, что в нем тестировал код).
Попробовал вынести из onCreate. Через кнопку, срабатывают только runn2 и runn3.
Я думаю что вызывать этот метод из основного потока просто нет никакого смысла
Неправильный вывод. Я же говорю, что ты загрузил UI-поток всякими sleep'ами, из-за чего он не обновляется. Закомментируй
tvInfo.post(runn2); и появится run1. Нужно просто понимать, как отрабатывает твое приложение.
Вы абсолютно правы. Теперь вижу, что runn1 отрабатывает из основного потока. Да, это важно для понимания всего механизма работы приложения. Спасибо.

Turkovsky
Сообщения: 1
Зарегистрирован: 22 авг 2015, 11:31

Re: Урок 85. Еще несколько способов выполнения кода в UI-пот

Сообщение Turkovsky » 22 авг 2015, 11:45

damager82 писал(а): Первые два похожи и отправляют Runnable на немедленную обработку. Я не знаю в чем их принципиальное отличие. Если у вас есть соображения на этот счет, пишите на форуме в ветке этого урока.
Метод runOnUiThread принадлежит активности, а post принадлежит конкретному виджету.
Собственно, я Runnable-объекты не выносил, а прописывал сразу:

Код: Выделить всё

MainActivity.this.runOnUiThread(new Runnable()
{
   @Override
   public void run()
   {
      MainActivity.this.buttonOne.setText("text1");
      MainActivity.this.textViewOne.setText("text2");
   }
});
Таким образом, можно обращаться к нескольким разным виджетам, чего в post, насколько знаю, делать нельзя.

donec
Сообщения: 2
Зарегистрирован: 26 фев 2018, 06:19

Re: Урок 85. Еще несколько способов выполнения кода в UI-пот

Сообщение donec » 26 фев 2018, 06:27

Подскажите почему в классе MyTimerTask (класс в отдельном файле) не видно textView из MainActivity? Саму MainActivity видит.
20.png
20.png (34.84 КБ) 13083 просмотра

Ответить