LVMC (a.k.a. MVVM: ViewModel + DataBinding) と Fat View

LVMC(Android の MVVM)モデルや DataBinding について大体の感じはつかめてきたが、先日、一つ失敗して、学習したことがあった。

ViewModel + DataBinding を使うことによって、LifeCycle でグチャグチャに分断された Activity のあちこちに詰め込まれたコードを ViewModel や View に退避して、Activity をスッキリさせることには成功した。

一方、Activity から追い出したコードを、ViewModel に所属させるのか、View に所属させるのかという部分で間違いを犯した。DataBinding で View のプロパティを LiveData でリアルタイムに反映させることができるのだからと、ほとんどの部分を View に移植したのだ。これが失敗だった。

これは ViewModel が導入される以前の、Activity の肥大化に悩んだ当時の開発者たちが採った Fat View と呼ばれるアプローチと同じもので、Activity が一手に引き受けていた複雑な処理を、View が肩代りするだけの話に過ぎない。もちろん、通常は、Activity と View は一対多の関係だから、Activity に複数の View にまつわる処理が集結するよりはマシだが、単純に View の数に分割されただけで、全体としての複雑さの総量に変化はない。

今回は ViewModel を使っているにもかかわらず、単なる Fat View 的なアプローチと同じ罠に陥るという過ちを犯してしまったわけである。

Fat View の何がいけないかというと、View のプロパティにセットした値が、View で処理される順序が、何ら保証されていないという点である。今回は、ImageView を拡張して、Glide によるリモート画像の読み込みを行うようなことを実現したかったのだが、リモートのアドレスをバインドされた LiveData を通じてダイナミックに設定しようとした。ところが、リモートのアドレスをいくつかの諸条件から組み合わせて動的な生成を行う処理を View 内部に持たせ、バラバラの諸条件を View のプロパティとして入力しようとしたため、アドレスが null の段階で Glide で読み込もうとしたりと、処理が時系列的に制御不能な状態になった。

結局、そのような Fat View アプローチが間違っていたわけで、「View に考えさせてはいけない」ということに至った。「複雑に変化する諸条件から導き出されるアドレスについて思考する部分は ViewModel 内部において行い」、最終的な URL のみを LiveData として View に対して晒すというのが正解だったわけである。

最初はともかく、Activity をスッキリさせることだけに主眼があったが、まだそれだけでは片手落ちだったと思う。

  1. Activity からコードを追い出すことで、Activity のライフサイクルからは解脱することができる。そうなったら次は……
  2. ViewModel と View の間の、Model と View としての役割分担。両者の間の配分は DataBinding による Observed と Observer の関係をよく弁えた配分が必要になる。

コメント

人気の投稿