Android UI変更メカニズム
メインスレッドでUI変更メカニズムを簡単に理解してみましょう.UIがいつ変更されるか、変更されないかを理解している場合は、コードをより正確に記述できます.
UIを変更する方法はTextViewの方法と同じで、主にsetXxx()です.また,カスタムビューを作成する場合,このようなsetterメソッドを作成する際には,POJO(plain old java object)のように単純な代入のみを行うエラーも発生する.値を1つ指定すればいいわけではありません.invalidate()メソッドを呼び出して再描画する必要があります.
invalidate()メソッドの呼び出しスタックを確認する
invalidate()から始まるメソッドに従います.
Viewのinvalidate()メソッドは、親View Groupで自分の領域を再描画する必要があることを示す、ViewのinvalidateChild(ViewChild,final Rect dirty)メソッドを呼び出します.
invalidateChild()メソッドはdowhile文で親を親とします.invalidateChildInParent(location,drity)を置き換え、親がnullでない場合に呼び出しを続行します.(親がRootじゃないまで)
ここでは
したがって、親ビューグループを取得する方法は、
現在親がRootである場合、 dowhile文では、View/View Groupが再描画した領域を上に渡し、どうしても一番上に渡します.最上級はやはり
しかし論理を分離するために,仮想は別の位相を作成した.これはすなわちinvalidateChild()メソッドは、dowhile文でViewRootImplのinvalidateChildInParent(int[]location,Rectdirty)を最終的に呼び出す. ViewRootImplでは、invalidateChildInParent()の主なタスクはscheduleTrearsals()メソッドを呼び出すことです.scheduleTransversals()メソッドは、無効な(無効な)領域を再描画するためにポーリング(遍歴)タスクをスケジュールします.
スケジュールは既にメインLooperのMessageQueueにMessageを入れていたが、JellyBinからChoreogerに再依頼.
invalidateChild(), invalidateChildInParent() Deprecated
onDescentInvalidate()を使用する必要があります. invalidate()呼び出しスタック
しかし、運転後、画面は1秒ごとに変化せず、5秒後に最後に入れた
TextViewのsetText()メソッドは論理的に複雑で、最終的にはinvalidate()メソッドを呼び出して再描画する必要があります.ここに疑問があります.setText()でinvalidate()を実行するたびに5秒以内に描画できませんが、invalidate()では
Q.では、
そうではない.
Viewでは、mPrivateFlagsタグを使用して、メソッド内でinvalidate()を複数回呼び出しても、1回目の呼び出しだけで
ビューのinvalidateInternal()メソッドの先頭に
1)最初の無効な内部()メソッドのif文でタグを変更する
2)次のinvalidate()呼び出しでは、invalidateInternal()メソッドのif文からフィルタリングされ、ViewRootImplには到達しません.
すなわち,メソッド内で
しかし、無効な()メソッドを継続させることはできません.描き終わってinvalidate()を呼び出すと、もう一度描きますから.
Viewの
Referenceアンドロイド https://velog.io/@sery270/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-UI%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%97%85%EB%8D%B0%EC%9D%B4%ED%8A%B8-%EB%90%A0%EA%B9%8C
UIを変更する方法はTextViewの方法と同じで、主にsetXxx()です.また,カスタムビューを作成する場合,このようなsetterメソッドを作成する際には,POJO(plain old java object)のように単純な代入のみを行うエラーも発生する.値を1つ指定すればいいわけではありません.invalidate()メソッドを呼び出して再描画する必要があります.
public void setTitle(String title) {
this.title = title;
invalidate(); // 1)
}
書き直すには、1)
のようにinvalidate()
メソッドを呼び出してから메인 Looper의 MessageQueue
に入り、次のタイミングで画面に描く必要があります.これは、onDraw()にパラメータ伝達として反映されるtitle
である.invalidate()メソッドの呼び出しスタックを確認する
invalidate()から始まるメソッドに従います.
View.invalidate()
ViewGroup.invalidateChild()
parent = parent.invalidateChildInParent() : ViewGroup.invalidateChildInParent()
parent = parent.invalidateChildInParent() : ViewRootImpl.invalidateChildInParent()
ViewRootImpl.scheduleTraversals() : traversal 작업을 스케줄링
ViewRootImpl.performTraversal() : traversal 작업을 실행 (draw 메세지를 보냄)
Viewのinvalidate()メソッドは、親View Groupで自分の領域を再描画する必要があることを示す、ViewのinvalidateChild(ViewChild,final Rect dirty)メソッドを呼び出します.
invalidateChild()メソッドはdowhile文で親を親とします.invalidateChildInParent(location,drity)を置き換え、親がnullでない場合に呼び出しを続行します.(親がRootじゃないまで)
ViewParent 인터페이스
が表示されます.ViewにはgetView Group()という方法があるはずですが、この方法はありません.代わりにgetParent()メソッドが使用され、getParent()はView Parentを返します.したがって、親ビューグループを取得する方法は、
getParent()
を実行し、ビューグループとして選択することである.ViewGroup.invalidateChildInParent()
ではなくViewRootImpl.invalidateChildInParent()
が呼び出されます.ViewGroup(com.android.internal.policy.PhoneWindow$DecorView)
で、ここで再描画のメッセージを送ることもできます.しかし論理を分離するために,仮想は別の位相を作成した.これは
ViewRootImpl
類です.ViewGroupとViewRootImlはViewParentインタフェースを実現し、invalidateChildInParent()はViewParentインタフェースの方法である.スケジュールは既にメインLooperのMessageQueueにMessageを入れていたが、JellyBinからChoreogerに再依頼.
ViewRootImpl
のinvalidateChildInParent()は、まずcheckThread()メソッドを呼び出し、プライマリスレッドでない場合はCalledFromWrongThreadExceptionを生成する.invalidateChild(), invalidateChildInParent() Deprecated
View.invalidate()
ViewGroup.onDescendantInvalidated()
parent = parent.onDescendantInvalidated()
//다음 노드가 Root가 아닌 경우 (do-while문)
ViewGroup.onDescendantInvalidated()
//다음 노드가 Root인 경우
ViewRootImpl.onDescendantInvalidated()
ViewRootImpl.scheduleTraversals() : traversal 작업을 스케줄링
ViewRootImpl.performTraversal() : traversal 작업을 실행 (draw 메세지를 보냄)
invalidate()を複数回呼び出すとfun onClick(view: View) {
for (i in 0..4) {
currentValue.setText("Current Value=$i")
SystemClock.sleep(1000)
}
}
TextViewテキストを毎秒変換するコードのように見えます.しかし、運転後、画面は1秒ごとに変化せず、5秒後に最後に入れた
Current Value=4
のみが表示されます.5秒以内にメインスレッドを捉えたため、5秒以内に画面をリフレッシュできない.TextViewのsetText()メソッドは論理的に複雑で、最終的にはinvalidate()メソッドを呼び出して再描画する必要があります.ここに疑問があります.setText()でinvalidate()を実行するたびに5秒以内に描画できませんが、invalidate()では
ViewRootImpl
を経てscheduleTransversals()を実行し、MessageQueueで다시 그리기
メッセージを蓄積する必要がある場合があります.Q.では、
Current Value=0
からCurrent Value=4
まで、短時間で肉眼では中間過程が見えないように出力しているのではないでしょうか.そうではない.
Viewでは、mPrivateFlagsタグを使用して、メソッド内でinvalidate()を複数回呼び出しても、1回目の呼び出しだけで
ViewRootImpl
に渡すことができます.ビューのinvalidateInternal()メソッドの先頭に
mPrivateFlags
値でチェックされたif条件文が含まれます.1)最初の無効な内部()メソッドのif文でタグを変更する
2)次のinvalidate()呼び出しでは、invalidateInternal()メソッドのif文からフィルタリングされ、ViewRootImplには到達しません.
すなわち,メソッド内で
invalidate()
を複数回呼び出しても,「再描画」のメッセージは1回だけ伝達される.しかし、無効な()メソッドを継続させることはできません.描き終わってinvalidate()を呼び出すと、もう一度描きますから.
Viewの
mPrivateFlags
はパッケージ化された変数であり、View、View Group、View RootImplの3つの場所で適切な変更を行うことでこの問題を解決します.Reference
<Next Step>
Reference
この問題について(Android UI変更メカニズム), 我々は、より多くの情報をここで見つけました https://velog.io/@woga1999/Android-UI-변경-메커니즘テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol