์๋ ํ์ธ์ :) ์๋๋ก์ด๋ ๊ฐ๋ฐ์ ํ๋ค๋ณด๋ฉด, tv.text = "hello"๋, tv.setText("World!")๋ก UI๋ฅผ ์ ๋ฐ์ดํธํ ๋๊ฐ ์๋๋ฐ์. ์ด๋ฐ ๋ช ๋ น์ด๊ฐ ์คํ๋ ๋ ๋ด๋ถ์ ์ผ๋ก ์ด๋ค์ผ์ด ์ผ์ด๋๋์ง ๊ถ๊ธํด๋ณด์ ์ ์์ผ์ ๊ฐ์ ? ์ ๋๋ฌด ๊ถ๊ธํ๋ค์. ์ค๋์ ์๋๋ก์ด๋์์ UI ๋ณ๊ฒฝ ๋งค์ปค๋์ฆ์ด ์ด๋ป๊ฒ ๋๋์ง ์์๋ณด๋ คํฉ๋๋ค. ์ค๋๋ ํ์ดํ ์ ๋๋ค ! ๐ฟ
๋ทฐ ๊ณ์ธต ๊ตฌ์กฐ, ์ฆ ๋ถ๋ชจ์๊ฒ ๋ค์ ๊ทธ๋ ค์ ธ์ผํจ์ ์๋ ค์ฃผ๋ ์ฒ๋ฆฌ์ ๋๋ค.
๋ทฐ๋ฅผ ๊ทธ๋ฆฌ๋ ์์ ์ด ์๋, ์์ ์ ๋ถ๋ชจ์๊ฒ ๋ณ๊ฒฝ์ฌํญ์ด ์๊ฒผ์์ ์๋ ค์ฃผ๋ ์์ ์ ๋๋ค.
The process of causing things to be redrawn
ํ๋ ์์ ๊ทธ๋ฆฌ๋๋ฐ ํ์ํ ๋ชจ๋ ๋จ๊ณ์ ์ํํ๋ ์ฒ๋ฆฌ์ ๋๋ค.
๋ทฐ์ ํฌ๊ธฐ ์ธก์ measure, ๋ทฐ์ ์์น ๋ฐ ํฌ๊ธฐ ๋ฐฐ์น layout, ๋ทฐ๋ฅผ ๊ทธ๋ฆฌ๊ธฐ draw ํ๋ ์ฒ๋ฆฌ๋ฅผ ์ผ์ปซ์ต๋๋ค.
traversal ์งํ draw()๊ฐ ํธ์ถ๋ฉ๋๋ค.
Performing all phases of rendering for a frame
View.invalidate()
View.invalidate()๋ฅผ ํธ์ถํ์ฌ, ๋ทฐ ๋ณ๊ฒฝ์ ์ํ invalidate ์์ ์ ์์ํฉ๋๋ค. View.invalidate()๋ ๋ด๋ถ์ ์ผ๋ก ํ์ฌ์ ๋ถ๋ชจ์๊ฒ invalidate ์์ ์ ์๋ฆฌ๊ธฐ ์ํด, ViewGroup.invalidateChild()๋ฅผ ํธ์ถํฉ๋๋ค.
ViewGroup.invalidateChild()์์ , ๊ณ์ํด์ ๋ถ๋ชจ์๊ฒ invalidate ์์ ์ ์๋ฆฌ๊ฒ ๋ฉ๋๋ค. ํด๋น ์์ ์ do-while๋ฌธ์ ํตํด ๋ฐ๋ณต๋ฉ๋๋ค. ์ด ๋ฐ๋ณต์์์ , ViewGroup.invalidateChildInParent()๊ฐ ํธ์ถ๋๋๋ฐ, ์ด ๋ถ๋ถ์ด ๋ฐ๋ก ๋ถ๋ชจ์๊ฒ invalidate ์์ ์ ์๋ฆฌ๋ ๋ถ๋ถ์ ๋๋ค. ๋ค๋ง ์ด ๋ฐ๋ณต์ ํ์ฌ์ ๋ถ๋ชจ๊ฐ Root๊ฐ ์๋๋๊น์ง๋ง ๋ฐ๋ณตํ๊ฒ ๋ฉ๋๋ค.
๋ง์ฝ, ํ์ฌ์ ๋ถ๋ชจ๊ฐ Root๋ผ๋ฉด, ViewGroup.invalidateChildInParent() ๋์ ViewRootImpl.invalidateChildInParent()๊ฐ ํธ์ถ๋ฉ๋๋ค. ์ฆ, do-while์ ๋ง์ง๋ง ํธ์ถ์ ViewRootImpl.invalidateChildInParent()๊ฐ ๋ฉ๋๋ค.
ViewRootImpl.invalidateChildInParent()์์ traversal ์์ ์ด ์์๋ฉ๋๋ค. ํฌ๊ฒ scheduleTraversals() ์ performTraversal() ๋ก ๋๋์ด ์ค๋ช ํ๊ฒ ์ต๋๋ค.
ViewRootImpl.scheduleTraversals() ์ ๊ธฐ์กด์ MainLooper์ MessageQueue์ ์ง์ Message๋ฅผ ๋ฃ์์ง๋ง, ์ ค๋ฆฌ๋น ๋ถํฐ๋ Choreographer์๊ฒ ์์ํ๋ค๊ณ ํฉ๋๋ค. ํด๋น ์์ ์ ์์ํ ๋ฟ, MainLooper์ MessageQueue์ Message๋ฅผ ๋ฃ๋ ๊ฑด ๋ณํจ ์์ต๋๋ค.
ViewParent์ invalidateChild() , invalidateChildInParent()๊ฐ DEPRECATED๋์ด, onDescendantInvalidated()๋ฅผ ์ฌ์ฉํด์ผํฉ๋๋ค. ์ ๊ทธ๋ฆผ๋ค์ ๋ฐ์ํด๋ณด๋ฉด ์๋์ ๊ฐ์ต๋๋ค.
์๋ ์ฝ๋๋ ํ๋ฉด์ ์๋์ผ๋ก ์ ๋ฐ์ดํธํ๋ ์์ ์ ์๋ํ ์ฝ๋์ ๋๋ค. 1์ด์ฉ์ ํ ์ ๊ฐ์ง๋ฉฐ, 0๋ถํฐ 4๊น์ง์ ์ซ์๊ฐ ํ๋ฉด์ ๋ณด์ฌ์ง๊ฒ ๋๋, ์ฆ 5๋ฒ์ ํ๋ฉด ์ ํ์ 1์ด ๊ฐ๊ฒฉ์ผ๋ก ํ๊ฒ ํ๋ ์ฝ๋๋ฅผ ์์ฑํ๊ณ ์ถ์์ต๋๋ค. 1์ด์ฉ sleep ํด์ฃผ๋ฏ๋ก์จ, ํ๋ฉด ์ ๋ฐ์ดํธ์ ํ ์ ์คฌ์ผ๋ ์ ๋๋ก ์๋ํด์ผ ๊ธฐ๋ถ์ด ์ข์ ๊ฒ ๊ฐ์ต๋๋ค. ๊ณผ์ฐ ์ด ์ฝ๋๊ฐ ์ ๋๋ก ์๋ ๋ ๊น์?
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById<Button>(R.id.button).setOnClickListener {
Log.d("setOnClickListener", SystemClock.uptimeMillis().toString())
onClick(findViewById<TextView>(R.id.text_view))
}
}
fun onClick(view: TextView) {
for (i in 0..4) {
view.text = i.toString()
Log.d("for ๋ฌธ ${i}๋ฒ์งธ", SystemClock.uptimeMillis().toString())
SystemClock.sleep(1000)
}
}
}
์ ๊ฐ์ค๋ฝ๊ฒ๋, ์ ์ฝ๋๋ ์๋์ฒ๋ผ ์๋๋ฉ๋๋ค. ์๋๋ก์ด๋ ๊ฐ๋ฐ์ ์ ๋ฌธํ์๋ฉด์, ์๋์ ๊ฐ์ ์ค์๋ฅผ ์ ์ง๋ฌ๋ณธ ๊ฒฝํ์ด ์์ผ์ค๊ฒ๋๋ค. (ใ ใ )
๊ธฐ์กด ์ดํด๋ฅผ ์ ์ฉํด๋ณธ๋ค๋ฉด, ์๋ ๊ณผ์ ์ด ์์ฐจ์ ์ผ๋ก 5๋ฒ ๋ฐ๋ณต๋์ด์ผํฉ๋๋ค.
invalidate() โ performTraversal() โ draw Message โ Sleep
๋ฐ๋ผ์, ์๋ ๊ทธ๋ฆผ๊ณผ ๊ฐ์ด ์์ ์ด Enqueueing ๋ฉ๋๋ค. queueing๋ ์์๋๋ก ์์ ์ด ์ด๋ฃจ์ด์ง๊ฒ ๋์ฃ . ์ฆ, MessageQueue์ 0์ ๊ทธ๋ฆฌ๋ ๋ฉ์ธ์ง๋ถํฐ 4๋ฅผ ๊ทธ๋ฆฌ๋ M๊น์ง ์ฐจ๋ก๋๋ก enqueue ๋๋ค๊ณ ์ดํด๋ฉ๋๋ค.
์ข์ ๊ธ ๊ฐ์ฌํฉ๋๋ค!
ํน์ ๋ค์๊ณผ ๊ฐ์ ์ฝ๋์์
CoroutineScope(Dispatchers.IO).launch { binding.searchEditText.setText("1234") }
์ฑ์ด ํฌ๋์๊ฐ ๋์ง ์๊ณ ์ ์์ ์ผ๋ก ์๋ํ๋ ์ด์ ๊ฐ ์์ ๋ณธ๋ฌธ๊ณผ ๊ด๋ จ์ด ์๋ ๋ด์ฉ์ผ๊น์?
Ui ๊ด๋ จ ๋ณ๊ฒฝ ์์ ์ ๋ฉ์ธ ์ค๋ ๋ (Ui ์ค๋ ๋)์์ ํด์ผ๋ง ํ๋ค๊ณ ์๊ณ ์์๋๋ฐ ์๋๋์ด์ ๋ญ๊ฐ ์์ํด์ ํด๋น ๋ด์ฉ์ ๊ฒ์ํด๋ณด๋ค๊ฐ ์จ์ฃผ์ ๊ธ์ ์ฝ์ด๋ณด๊ฒ ๋์์ต๋๋ค ใ