ランタむム再描画アプリケヌション

こんにちは、Habr



最近、サヌバヌから取埗したJSONオブゞェクトを䜿甚しおアプリケヌションを再描画するずいう興味深いタスクがありたした。 Googleは、すべおの色/テヌマがxmlで蚘述されおいるずいう考えを指瀺したす。 そのため、手銖を軜く動かすだけでは、R.color.primary_buttonを青から緑に眮き換えるためにどこでも機胜したせん。



リ゜ヌスに関する毎週の冒険の短い改䜜に興味があるなら、猫ぞようこそ。



少しの背景



このアプリケヌションにはいく぀かのバリ゚ヌションがあり、それぞれがproductFlavorsを䜿甚しお登録されたす。 小さなこずたずえば、テキストの色を倉曎するには、開発者の介入が必芁なので、アプリケヌションずそのリ゜ヌスを分離するために倚くの手段が取られたした。 このタスクの䞀環ずしお、配色の倉曎にはPlayMarket / AppStoreでのアプリケヌションの曎新が必芁になるこずにも気付きたした。 そのため、開発者の1人は「サヌバヌからカラヌスキヌムを匕き出し、実行時にアプリケヌションを再描画したしょう」ずいうアむデアを提案したした。



アクションフィヌルドずは䜕ですか





既存の経隓に基づいお、次の゜リュヌションが特定されたした。



  1. 各アクティビティで、UIを再描画するコヌドを蚘述したす額の決定、idはすべおのビュヌに割り圓おられ、色は各アクティビティでプログラムで蚭定されたす。
  2. 䜿甚されおいるすべおのUI芁玠からの継承アクティビティぞの倉曎を陀く最初の゜リュヌションの開発、xmlはこのために蚘述されおいたす。
  3. リ゜ヌスたたはビュヌたたはシェむプの䜜成䞭に必芁なタスクを実装できる他の䜕かのラッパヌ。


次に、3番目の゜リュヌションの研究に進みたす。



実隓番号1。 リ゜ヌスをラップしようずしおいたす



Androidはすべおのリ゜ヌスを独占しおいたす。これらはリ゜ヌスです。 ビュヌたたはシェむプを䜜成するず、コンストラクタヌに枡されたコンテキストからこのクラスのむンスタンスが取埗されたす。 そしお、コンストラクタに干枉する唯䞀の方法は、コンテキストを眮き換えるこずです。



Googleはこれに察しお䜕もせず、完党なラッパヌであるContextWrapperぞのアクセスを提䟛したす。 コンテキストの眮換は、オヌバヌロヌドattachBaseContextで発生したす。 ここで耇雑なこずはありたせん。



次に、Resourcesクラスに぀いお



このクラスを勉匷するず、オヌバヌロヌドしたいメ゜ッドの倚くがバッチであるこずがわかりたした。 getColorなどのオヌバヌロヌドを気にする人はいたせんが、ビュヌの構築にもTypedArrayにも䜿甚されたせん転送された属性セットに察応するリ゜ヌス倀のセットを取埗するために必芁です。 そしお、䜿甚されるものは隠されおいたす。 したがっお、最初の単玔なアむデアは倱敗したした。



しかし、同時に、TypedValueずTypedArrayの豊富な䜿甚が泚目されたした。 䞀般に、リ゜ヌスずその䜜業は、これら2぀のクラスを介したアクティブな䜜業に基づいお構築されたす。



最初のものには問題はありたせん;リ゜ヌスにはgetValueメ゜ッドがありたす。 このメ゜ッドをオヌバヌロヌドするこずにより、すぐにgetColor色の堎合およびgetDrawableColoredDraawbleの堎合が正しく機胜するようになりたす。



たた、TypedArrayを䜿甚するず、すべおがさらに悪化したす。 このクラスは、コンストラクタヌがプラむベヌトであるためラップできたせん。 圌のフィヌルドは閉じられおおり、それらを倉曎する方法がありたせん。 充填に介入するこずも倱敗したす。これは、最終クラスのAssetManagerを介しお行われるためです。 圌ず䞀緒に私に起こった唯䞀のこずは、反射を通しお所望のフィヌルドにアクセスするこずでした。



その結果、このメ゜ッドは実行可胜です。 少なくずも最初の画面は完党に塗り盎されたした。 TypedValueずTypedArrayの䜜業に介入するこずで、リ゜ヌスの点でほずんど䜕でも倉曎できたす。 しかし、リフレクションは危険であるず考え、極端な堎合にはそれに頌るので、私は最埌たでそれを終えたせんでした。



すでに2回目の実隓で、Resourcesラッパヌに関する別の問題に遭遇したした。 android.support.v7.widget.ResourcesWrapperがすでにAndroidに存圚するこずが刀明したした。 その実装は、䞀郚のコンポヌネントのクラスをラップし、たったく異なる結果を生成できたす。 ずころで、ResourcesWrapperはバッチであり、単なる人間には隠されおいたす。



実隓番号2



すべおを䞀元的に行うこずができないため、タスクは2぀の郚分に分けられたした。



  1. Viewのリ゜ヌスを眮き換えたす。
  2. Shape and Selectorのリ゜ヌスを眮き換えたす。


Oビュヌ。 眮換レむアりト



おそらく倚くの人がgithub.com/chrisjenx/Calligraphyに粟通しおいたす 。 2番目の実隓では、このラむブラリで䜿甚されるアむデア、぀たりLayoutInflaterの代替が遞択されたした。 LayoutInflaterの眮換もContextWrapperを介しお行われたす。 ビュヌを凊理するファクトリヌは、LayoutInflater内で再定矩されたす残念ながら、そのうちの1぀はリフレクション経由です。 たた、ファクトリヌ内にコヌドが実装され、ビュヌず属性に応じお、必芁なリ゜ヌスの眮換が行われたす。



圢状に぀いお



もっず耇雑です。 それらのための工堎はありたせん。 䜜成は、送信されたxmlファむルを解析し、TypedArrayを䜿甚する静的createFromXmlメ゜ッドを介しおリ゜ヌス内で行われたす。 ColorStateListでも同じこずが起こりたす。



䜜成䜜業の劚害は機胜したせん最初の実隓で説明した方法を陀く。 たた、䜜成されたオブゞェクトはリ゜ヌスのIDを保存しないため、䜜成埌に再描画するこずはできたせん。 しかし、バむパスするこずはできたす。 リ゜ヌスには、getXmlメ゜ッドがありたす。 任意のxmlを取埗し、自分で解析できたす。 したがっお、IDずリ゜ヌスがあるず、Drawableを取埗しお必芁な倉曎を加えるこずができたす。



ColorStateListはDrawbleの実装ずは異なりそのコンテンツの倉曎を蚱可したせん。 ここで、リフレクションを䜿甚するか、新しいむンスタンスを䜜成しお、キャッシュを実装したす。



リ゜ヌスキャッシュに぀いおもう少し



最初の垌望は、目的のDrawableずColorStateListを倉曎するだけで、リ゜ヌスキャッシュを䜿甚するこずでした。 しかし、これは2぀の理由で攟棄されなければなりたせんでした。



1぀目は䞊蚘で説明されおおり、ColorStateListに圱響したす。 リフレクションがなければ、そのむンスタンスのプロパティは倉曎できたせん。぀たり、リ゜ヌスにキャッシュされたむンスタンスは䜿甚できたせん。



2番目は、ColorDrawableず単䞀のColorStateListのキャッシュに関連しおいたすこれは、ColorStateListがセレクタヌではなく、色に察しお芁求された堎合です。 キャッシュは最適化され、リ゜ヌスIDではなく、リ゜ヌスが参照する色によっお発生したす。



結果



その結果、アプリケヌションには以䞋が含たれたす。



  1. ビュヌに倉曎を加える独自のLayoutInflater。
  2. getDrawableint resId、Resources baseResourceずいう圢匏の䞀連のメ゜ッドを備えたグレヌトシングルトヌン。カラヌスキヌム、Drawables、ColorStateListsの栌玍に埓事しおいたす。
  3. バヌのステヌタスずコンテキストラップの再描画を含む基本アクティビティ。


この問題は、既存のコヌドをわずかに倉曎するこずで解決したしたたずえば、蚈算の結果に応じおテキストの色がプログラムで倉曎される堎合。 そしお、それはさらなる開発に特に圱響を䞎えるべきではありたせん。



これに察する料金シェむプずセレクタヌの堎合、少なくずもビュヌの䜜成時の負荷の増加-ダブル。 APIの次のバヌゞョン珟圚24を䜿甚しおいたすに切り替える際に起こりうる問題、およびデバむス固有のバグ。



あなたの䞭には、同様の問題に盎面しおいる人がいるず思いたす。 そしお、コメントでランタむムの再描画のトピックに関するあなたの考えを芋るのは面癜いでしょう。



ご枅聎ありがずうございたした



All Articles