Що саме робить метод публікації?


106

Я стикався з дуже дивною рисою.

Коли я намагаюся запустити анімацію на основний потік, вона не запускається. Коли я запускаю зазначену анімацію, використовуючи

getView().post(new Runnable() {
            @Override
            public void run() {
                getView().startAnimation(a);
            }
        });

Це все-таки починається.

Я надрукував CurrentThreadперед початком анімації та обидва друку main.

Очевидно, мені щось тут не вистачає, тому що обидва повинні почати анімацію на головній нитці ... Я здогадуюсь, що коли пост додає завдання до черги, вона починається в більш "правильний час", але я хотів би знати що відбувається тут на більшій глибині.

EDIT: Дозвольте мені прояснити речі - моє запитання полягає в тому, чому запуск анімації після публікації викликає її запуск, коли запуск анімації на основній темі не робить.


Чи специфічна така поведінка для версії Android? Я не зміг його відтворити на Android 4.1.2!
Акденіз

Я відтворив цю поведінку на Android 2.3.3. Але для AnimationDrawable! Звичайний Animationекземпляр почав успішно анімувати під час кожного налаштування. У AnimationDrawableвипадку; коли ви намагаєтеся запустити його onCreate, він не починається через те, що не приєднаний до перегляду в цей момент. Тож це питання не для різьблення AnimationDrawable. Може, те саме стосується і Animation? developer.android.com/guide/topics/graphics/…
Акденіз

Відповіді:


161

post : post спричиняє додавання Runnable до черги повідомлень,

Виконання: представляє команду, яку можна виконати. Часто використовується для запуску коду в іншій темі.

run () : запускає виконання активної частини коду класу '. Цей метод викликається при запуску потоку, створеного з класом, який реалізує Runnable.

getView().post(new Runnable() {

         @Override
         public void run() {
             getView().startAnimation(a);
         }
     });

код :getView().startAnimation(a);

у своєму коді,

post викликає Runnable ( код буде запущений у різному потоці) для додавання черги повідомлень.

Тож startAnimation буде запущений у новій темі, коли він отриманий із повідомленняQueue

[EDIT 1]

Чому ми використовуємо новий потік замість потоку інтерфейсу (основний потік)?

Нитка інтерфейсу користувача:

  • Коли програма запущена, нитка Ui створюється автоматично

  • він відповідає за пересилання подій до відповідних віджетів, і це включає події малювання.

  • Це також нитка, з якою ви взаємодієте з віджетами Android

Наприклад, якщо ви торкаєтесь кнопки на екрані, потік інтерфейсу передає подію дотику до віджета, який, у свою чергу, встановлює його натиснутий стан і розміщує недійсний запит у черзі подій. Нитка користувальницького інтерфейсу знімає запит і сповіщає віджет про перемальовування себе.

Що станеться, якщо користувач натисне кнопку, яка буде робити довгуоперацію?

((Button)findViewById(R.id.Button1)).setOnClickListener(           
             new OnClickListener() {        
        @Override
    public void onClick(View v) {
            final Bitmap b = loadImageFromNetwork();
            mImageView.setImageBitmap(b);
}
});

Інтерфейс заморожується. Програма може навіть вийти з ладу.

public void onClick(View v) {
  new Thread(new Runnable() {
    public void run() {
        final Bitmap b = loadImageFromNetwork();
        mImageView.setImageBitmap(b);
    }
  }).start();
}

Це порушує правило Android, яке ніколи не оновлює інтерфейс користувача безпосередньо з робочої нитки

Android пропонує кілька способів доступу до потоку інтерфейсу користувача з інших потоків.

  • Activity.runOnUiThread (Runnable)
  • View.post (Runnable)
  • View.postDelayed (Виконується, довго)
  • Обробник

Як і нижче,

View.post (Runnable)

public void onClick(View v) {
  new Thread(new Runnable() {
    public void run() {
      final Bitmap b = loadImageFromNetwork();
      mImageView.post(new Runnable() {
        public void run() {
          mImageView.setImageBitmap(b);
        }
      });
    }
  }).start();
}

Обробник

final Handler myHandler = new Handler(Looper.getMainLooper());

(new Thread(new Runnable() {

    @Override
    public void run() {
       final Bitmap b = loadImageFromNetwork();
      myHandler.post(new Runnable() {                           

        @Override
        public void run() {
           mImageView.setImageBitmap(b);
          }
        });
      }
    })).start();                
}

введіть тут опис зображення

Для отримання додаткової інформації

http://android-developers.blogspot.com/2009/05/painless-threading.html

http://www.aviyehuda.com/blog/2010/12/20/android-multithreading-in-a-ui-environment/


15
Так чому ж запуск анімації на посаді відрізняється від запуску її на головній нитці, коли вони в кінцевому підсумку працюють на одній темі?
Гал

Оскільки ця модель з однією ниткою може забезпечити низьку продуктивність в додатках Android.
Талха

1
Що стосується поганої продуктивності, якщо не показує анімацію?
Гал

17
Я не думаю, що це відповідає на це питання, це більше схоже на загальну відповідь для початківців, які нічого не знають про ui-потоки та багатопотокові нитки. Це не пояснює, чому пересування анімації вперед у черзі змушує анімацію працювати; анімація повинна бути чимось виконаним безпосередньо в ui-потоці, не використовуючи жодних трюків post () або runOnUiThread ().
carrizo

3
Всі роботи інтерфейсу повинні бути на головній нитці (потоці інтерфейсу). Трюк, який змушує анімацію працювати, використовуючи post () замість виклику в основному потоці відразу, це час: якщо ви зателефонуєте відразу в основний потік, це означає, що ви сказали "запустити анімацію зараз", але наразі перегляд може не готовий для анімації (міряти, малювати ...). Але якщо ви поставите це у post (), воно очікує startAnimation у черзі колись для підготовки перегляду, готового до анімації.
NguyenDat

35

Це робиться на onCreate чи onCreateView? Якщо це так, додаток може не знаходитися в стані, коли Перегляд додається до вікна. Багато алгоритмів, заснованих на показниках перегляду, можуть не працювати, оскільки такі показники, як вимірювання та положення Перегляду, можливо, не були обчислені. Android-анімація зазвичай вимагає їх за допомогою математики інтерфейсу користувача

View.post насправді чергає анімацію в циклі повідомлень View, тож як тільки представлення приєднується до вікна, воно виконує анімацію, а не виконує її вручну.

Ви фактично запускаєте речі в потоці інтерфейсу користувача, але в інший час


Прийнята відповідь вводить в оману, коли плакат стверджує, що "публікація викликає Runnable (код буде запускатися a в іншій потоці)" Це правильна відповідь "Ви фактично запускаєте речі в потоці інтерфейсу користувача, але в інший час" - плюс 1
smitty1

18

Подивіться тут на гарну відповідь. view.post () - це те саме, що і handler.post (). Він переходить до черги основного потоку і виконується після завершення інших очікуваних завдань. Якщо ви зателефонуєте Activity.runOnUiThread (), він буде викликаний негайно в потоці інтерфейсу користувача.


31
Я знайшов одну велику (і надзвичайно корисну) різницю, яку можна виконати у view.post (), коли вона буде показана вперше. IE, ви можете встановити його, щоб запустити анімацію після інфляції Перегляду, а потім у якийсь момент, нарешті, додати її до ієрархії перегляду. Після цього анімація виконається, і вам не доведеться турбуватися про це.
DeeV

Насправді, handler.post () не завжди публікує повідомлення / виконується в основній темі. Це залежить від того, як створено обробник (його можна пов’язати із Looper на іншій нитці). З іншого боку, view.post () завжди працюватиме на головній темі
Яїр Кукієлка

4

Я думаю, що проблема може бути методом життєвого циклу, коли ви викликаєте метод post (). Ви робите це в onCreate ()? якщо так, подивіться, що я знайшов у документації onResume () про діяльність:

onResume ()

Додано в API рівня 1 void onResume () Викликається після onRestoreInstanceState (Bundle), onRestart () або onPause (), щоб ваша діяльність почала взаємодію з користувачем. Це гарне місце для початку анімації , відкритих пристроїв ексклюзивного доступу (наприклад, камери) тощо.

https://developer.android.com/reference/android/app/Activity.html#onResume ()

Отже, як сказав Джо Плант, можливо, перегляд не готовий запускати анімацію в той момент, коли ви дзвоните поштою (), тому спробуйте перенести її на onResume ().

PD: Насправді, якщо ви пересунете код на onResume (), я думаю, ви можете видалити виклик post (), оскільки ви вже є в ui-потоці, і перегляд повинен бути готовий до запуску анімації.


3
onResumeможе викликатися декілька разів (екрани переходять у режим сну, активність підштовхується до заднього кута тощо) після того, як це буде спочатку, коли "перегляд готовий". Якщо зателефонували з onResume, може знадобитися прапор для відстеження погоди, коли анімація вже запущена, щоб уникнути (повторного) запуску кілька разів.
samis
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.