2018/2/9 DroidKaigi 2018 DAY02 room1 10:30~ 発表の付録1
DroidKaigi 2018付録1詳解RelativeLayoutの内部実装株式会社ノハナ 瀬戸優之@seto_hi
View Slide
RelativeLayoutのポイント=Graph
Graphグラフ(英: Graph)とは、ノード(頂点)群とノード間の連結関係を表すエッジ(枝)群で構成される抽象データ型、and・orその実装である具象データ型である。(wikipedia)
DependencyGraph● 有向グラフ● mNodes = 子Viewすべて、ArrayList● mKeyNodes = IDを持つ子View、SparseArrayNode● dependents = 参照しているNode● dependencies = 参照されているNode
RelativeLayout#onMeasure
RelativeLayout#onMeasure1. DependencyGraphを作る2. 横方向でGraphのrootからmeasure、仮レイアウト3. 縦方向でGraphのrootからmeasure、仮レイアウト○ 自身のサイズも仮決定
RelativeLayout#onMeasure4. 自身がwrap_contentなら○ 子のサイズとMeasureSpecから自身のサイズを修正○ 中央寄せのViewの位置を修正5. Gravityによって位置を本決め6. setMeasuredDimensions
mesureでの仮レイアウト● 参照のGraphのrootからmeasure + 仮レイアウトしていく● measure対象のViewが参照しているViewは必ず仮レイアウト済み● measureさえすればmeasure対象のViewの仮レイアウト位置が確定できる
子ViewのmeasureSpec1. 左右(or上下)ともに参照しているViewがある○ 左右(or上下)のViewの間のサイズ + EXACTLY2. 1.でない場合○ 子Viewがサイズ決め打ち■ 子Viewのサイズと余りサイズの最小値 + EXACTLY○ 子Viewがmatch_parent■ RelativeLayoutの余りサイズ + EXACTLY※○ 子Viewがwrap_content■ RelativeLayoutの余りサイズ + AT_MOST※※余りがなければ0 + UNSPECIFIED
RelativeLayout#onLayout
RelativeLayout#onLayout● measure通りにレイアウトするだけ○ RelativeLayout.LayoutParamsが位置と座標を持つ■ mLeft, mTop, mRight, mBottom● シンプル!
循環参照の検知
循環参照の検知● RelativeLayoutで循環参照は禁止○ rightOfのleftOfが自身のような場合○ ConstraintLayoutは一部OK(Chainになる)● グラフの参照で解決
DependencyGraph● mNodes = 子Viewすべて、ArrayList● mKeyNodes = IDを持つ子View、SparseArrayNode● dependents = 参照しているNode● dependencies = 参照されているNode
DependencyGraph#getSortedViews1. GraphのrootをDequeに入れる2. Dequeからグラフの頂点のNodeをpoll3. 2.を参照している子Nodeに対して3.1. 参照されているNodeがないならばDequeに追加3.2. 参照されているNodeがあれば何もしない4. Dequeが空ならば5、Dequeが空でないならば2.に戻る5. すべてのEdgeをDequeに追加できていない場合は例外を投げる
循環参照の検知(正常系)ABCDequeue
循環参照の検知(正常系)ABCDequeueA1.RootをDequeueに追加
循環参照の検知(正常系)ABCDequeueB2.pollして消去3.1.Dequeueに追加
循環参照の検知(正常系)BCDequeueC3.1.Dequeueに追加2.pollして消去
循環参照の検知(正常系)CDequeue2.pollして消去
循環参照の検知(正常系)Dequeue5.Dequeueが空ですべてのEdgeを参照したので終了
循環参照の検知(異常系)ABCDequeue循環参照
循環参照の検知(異常系)ABCDequeueA1.RootをDequeueに追加
循環参照の検知(異常系)ABCDequeue2.pollして消去3.2.参照があるのでDequeueに追加しない
循環参照の検知(異常系)BCDequeue5.Dequeueが空なのにすべてのEdgeが参照できていない例外を投げる