DEV_EASY_NOTES Telegram 21
​​{3/4} В этом посте используется код на Kotlin, просьба Java дИдов не пугаться!

Понемногу у нас с вами складывается картина того, каким образом работает UI в android. Мы разобрали что такое Looper, что такое Message и MessageQueue. Узнали, что в Looper посылаются задачи через MessageQueue. Возникает вопрос, как именно послать задачу в Looper, так как прямого доступа к MessageQueue у нас нет. Тут на сцену выходит Handler.

Прежде чем начнем разбирать Handler введем 2️⃣ понятия:
☝️поток consumer - поток, который ждет сообщения, тот, который вызывал Looper.loop().
✌️поток producer - поток, который создает сообщения и посылает их потоку consumer через Handler.
Поток consumer и поток producer могут быть одним потоком, как это может быть разберем далее.

Каждый Android разработчик хотя бы раз в своих проектах использовал Handler. Как уже сказано выше, нужен он для того, чтобы посылать задачи из потока producer в поток consumer.

У Handler есть несколько конструкторов, интересные пожалуй только 2️⃣ это:
☝️дефолтый коструктор без аргументов Handler()
✌️конструктор с аргументом типа Looper Handler(looper: Looper)

Когда используют конструктор без Looper, Handler пытается найти его через Looper.myLooper() и если его не находит, то падает.
Допустим в Activity.onCreate вы вызовете Handler().post{ doSmth() } - тут создается Handler, который через метод Looper.myLooper() получает Looper который привязан к Main Thread🧶, что аналогично записи Handler(Looper.getMainLooper()).post{ doSmth() }. Но если попытаемся тоже самое сделать на потоке без Looper, конструктор упадет💣:

Thread {
val handler = Handler() // - тут мы упадем
, так как у этого потока нет Looper🔁, подробнее смотри в посте про Looper
handler.post { doSmth() }
}.start()

Конструктор с входным параметром в виде Looper предпочтительнее, так как тогда вы явно задаете Looper🔁, в который будут post’иться сообщения. С ним все довольно очевидно, на вход нужно подать Looper в который будут посылаться задачи.

Теперь посмотрим на слудующий кусок кода:

fun onCreate() { // этот метод вызывает система
Handler().post {
Log.d("hello from handler thread ${Thread.currentThread().name}")
}
Log.d("hello from onCreate thread ${Thread.currentThread().name}")
}

Для начала попробуйте ответить сами, что будет выведено в лог В логах мы увидим следующую последовательность:

- "hello from onCreate thread main"
- "hello from handler thread main"

Когда вызываем метод post, переданный Runnable оборачивается в Message и через MessageQueue подается на Looper consumer потока. Однако система все методы жизненного цикла активности тоже вызывает через Looper потока Main🧶, даже сам метод onCreate() вызывался примерно так:

val activity = getCurrentActivity()
val handler = Handler()
handler.post {
activity.onCreate()
}

Следовательно, когда мы вызываем Handler().post{ Log.d("hello from handler thread ${Thread.currentThread().name}") } эта задача кладется в очередь и выполнится после того, как завершится метод onCreate().

Этот пример очень сильное упрощение того, что происходит на самом деле, но суть та же. Это тот случай, когда поток consumer и поток producer это один и тот же поток. Именно этим фактом, обуславливается асинхронность в UI. Когда мы создаем транзакцию для показа фрагмента, после метода commit эта транзакция также кладется в MessageQueue через Handler, и выполняется позже Looper’ом Main Thread🧶, также происходит и с показом новой🆕 Activity и многими другими вещами вроде анимаций и т.п.

Стоит упомянуть еще одну интересную особенность, так уж вышло, что огромное количество багов связаных с View на Android можно решить просто отложив задачу Handler().postDelayed(100) { //doSmth }.

Помните мы разбирали, что у Message есть специальное поле when, так вот, когда вызываем post у Handler, там используется SystemClock.uptimeMillis()), наподобие System.getCurrentTimeMillis(), а когда вызываем postDelayed, то входной аргумент delay прибавляется к SystemClock.uptimeMillis()) и записывается в поле when, а дальше магия сортировки, которая обсуждалась туть.
👍241🔥1



tgoop.com/dev_easy_notes/21
Create:
Last Update:

​​{3/4} В этом посте используется код на Kotlin, просьба Java дИдов не пугаться!

Понемногу у нас с вами складывается картина того, каким образом работает UI в android. Мы разобрали что такое Looper, что такое Message и MessageQueue. Узнали, что в Looper посылаются задачи через MessageQueue. Возникает вопрос, как именно послать задачу в Looper, так как прямого доступа к MessageQueue у нас нет. Тут на сцену выходит Handler.

Прежде чем начнем разбирать Handler введем 2️⃣ понятия:
☝️поток consumer - поток, который ждет сообщения, тот, который вызывал Looper.loop().
✌️поток producer - поток, который создает сообщения и посылает их потоку consumer через Handler.
Поток consumer и поток producer могут быть одним потоком, как это может быть разберем далее.

Каждый Android разработчик хотя бы раз в своих проектах использовал Handler. Как уже сказано выше, нужен он для того, чтобы посылать задачи из потока producer в поток consumer.

У Handler есть несколько конструкторов, интересные пожалуй только 2️⃣ это:
☝️дефолтый коструктор без аргументов Handler()
✌️конструктор с аргументом типа Looper Handler(looper: Looper)

Когда используют конструктор без Looper, Handler пытается найти его через Looper.myLooper() и если его не находит, то падает.
Допустим в Activity.onCreate вы вызовете Handler().post{ doSmth() } - тут создается Handler, который через метод Looper.myLooper() получает Looper который привязан к Main Thread🧶, что аналогично записи Handler(Looper.getMainLooper()).post{ doSmth() }. Но если попытаемся тоже самое сделать на потоке без Looper, конструктор упадет💣:

Thread {
val handler = Handler() // - тут мы упадем
, так как у этого потока нет Looper🔁, подробнее смотри в посте про Looper
handler.post { doSmth() }
}.start()

Конструктор с входным параметром в виде Looper предпочтительнее, так как тогда вы явно задаете Looper🔁, в который будут post’иться сообщения. С ним все довольно очевидно, на вход нужно подать Looper в который будут посылаться задачи.

Теперь посмотрим на слудующий кусок кода:

fun onCreate() { // этот метод вызывает система
Handler().post {
Log.d("hello from handler thread ${Thread.currentThread().name}")
}
Log.d("hello from onCreate thread ${Thread.currentThread().name}")
}

Для начала попробуйте ответить сами, что будет выведено в лог В логах мы увидим следующую последовательность:

- "hello from onCreate thread main"
- "hello from handler thread main"

Когда вызываем метод post, переданный Runnable оборачивается в Message и через MessageQueue подается на Looper consumer потока. Однако система все методы жизненного цикла активности тоже вызывает через Looper потока Main🧶, даже сам метод onCreate() вызывался примерно так:

val activity = getCurrentActivity()
val handler = Handler()
handler.post {
activity.onCreate()
}

Следовательно, когда мы вызываем Handler().post{ Log.d("hello from handler thread ${Thread.currentThread().name}") } эта задача кладется в очередь и выполнится после того, как завершится метод onCreate().

Этот пример очень сильное упрощение того, что происходит на самом деле, но суть та же. Это тот случай, когда поток consumer и поток producer это один и тот же поток. Именно этим фактом, обуславливается асинхронность в UI. Когда мы создаем транзакцию для показа фрагмента, после метода commit эта транзакция также кладется в MessageQueue через Handler, и выполняется позже Looper’ом Main Thread🧶, также происходит и с показом новой🆕 Activity и многими другими вещами вроде анимаций и т.п.

Стоит упомянуть еще одну интересную особенность, так уж вышло, что огромное количество багов связаных с View на Android можно решить просто отложив задачу Handler().postDelayed(100) { //doSmth }.

Помните мы разбирали, что у Message есть специальное поле when, так вот, когда вызываем post у Handler, там используется SystemClock.uptimeMillis()), наподобие System.getCurrentTimeMillis(), а когда вызываем postDelayed, то входной аргумент delay прибавляется к SystemClock.uptimeMillis()) и записывается в поле when, а дальше магия сортировки, которая обсуждалась туть.

BY Dev Easy Notes




Share with your friend now:
tgoop.com/dev_easy_notes/21

View MORE
Open in Telegram


Telegram News

Date: |

Over 33,000 people sent out over 1,000 doxxing messages in the group. Although the administrators tried to delete all of the messages, the posting speed was far too much for them to keep up. It’s easy to create a Telegram channel via desktop app or mobile app (for Android and iOS): In handing down the sentence yesterday, deputy judge Peter Hui Shiu-keung of the district court said that even if Ng did not post the messages, he cannot shirk responsibility as the owner and administrator of such a big group for allowing these messages that incite illegal behaviors to exist. With the “Bear Market Screaming Therapy Group,” we’ve now transcended language. More>>
from us


Telegram Dev Easy Notes
FROM American