@izumin5210さんがReduxのAndroid実装を作ってくれました。
私も最近、JSエンジニアに片足を突っ込み始めまして、React+Reduxを勉強し始めていたところだったので、本来の自分の土俵であるAndroid向けの実装を出していただけたおかげで、理解にかかる時間を削減できそうです。ありがたや。
私が今のところReact+Reduxについて良いと思っている点について、Droiduxだとどうなんだろうと思ったので、ちょっと備忘録として書き残しておきます。ほぼポエムです。
React+Reduxの雑な良さ
- データが更新されたら、見た目をそのデータ通りに変えたい
- 見た目を変えるためにいちいち画面全体を書き換えてたらコストがかかりすぎてチラついたりするので、画面の中でも変更があった箇所だけ更新したい
これらは、クライアントサイドのアーキテクチャとしてはよくある考え方だと思います。
MV*な場合
MV*なアーキテクチャでは、Modelが更新されたときに更新されたデータに関連するViewへデータが届くようにControllerやPresenterなどが交通整理を行い、状態の管理と描画コストのバランスをとっているイメージです。1も2も満たせていると思います。
ただし、この交通整理が曲者で、「このデータが変わったらViewのこの部分を更新する」という設定を頑張って書かないといけません。頭が悪いとつらいやつです。
React+Reduxな場合
Reduxは、StoreからViewへデータを渡すときに、今回更新するべきデータはどれなのかなどは一切考えず、表示したいデータ全体を渡しています。普通なら、前述の2の通り、「見た目を変えるためにいちいち画面全体を書き換えて」しまう方法です。Reduxでも、Viewの作り方次第では実際に描画コストの問題が起こってしまうでしょう。
ところが、ReduxのViewをReactで実装する場合、その問題は起こりづらくなります。「画面全体を書き換え」る対象は仮想DOMであり、本物のDOMが書き換わるのはそれまでの画面状態との差分を取って変更があった箇所だけです(雑な理解)。プログラマー側としては雑に画面全体を書き換える操作をしているのに、描画側は最小限のコストで収まるのです。
@izumin5210さんが仰る「雑な扱いができるので頭悪くてもとりあえずいい感じに使えそう」という話は、React+Reduxな状況では、実際そうっぽいなーと私も思っています。(勉強し始めで経験浅いので今後手を動かしながら別の意見を持つかもしれませんが)
ReduxはReactに依存しないアーキテクチャなのは分かりますが、Reactと一緒に使ったときに最も威力を発揮するアーキテクチャであるはずなので、この記事ではReact+Reduxは一緒に使うべきという方向で話を続けます。
DroiduxにとってのReactは誰?
さて、AndroidにはReactはいません。
前述のとおり、ReduxはStoreからViewに向かって雑にデータを投げつける形で画面更新を実現するため、Viewが描画コストを下げるための仕組みを持っていないと、見た目が悪くなってしまいかねません。
では、DroiduxにはReactはいるのでしょうか?
サンプルを眺めた限りでは、Adapterに可能性を感じました。
AdapterView + BaseAdapter
AdapterView、つまりListViewやGridViewにおいては、Reactと似たようなことが起こっているように思います。BaseAdapter#notifyDatasetChangedが、React的な「雑な扱い」を持っているのではないかなと。
ListView+ArrayAdapterを例に挙げると、こんな流れになるでしょうか。
- ArrayAdapterにリストデータへの参照を登録する
- ListViewにArrayAdapterを登録する
- いろいろあってリストデータを更新する
- ArrayAdapterのnotifyDatasetChangedを呼ぶ
- 最小限のコストでListViewが更新される
とりあえずデータを更新してnotifyDatasetChanged呼んどけばいいよね!みたいな雑さがあります。(本当にnotifyDatasetChangedのコストは低いのかと言われるとイマイチ自信がないですが)
サンプルで言うとこのへんかな。
public TodoListAdapter(Context context) {
super();
this.inflater = LayoutInflater.from(context);
this.store = ((App) context.getApplicationContext()).getStore();
this.store.observeTodoList().subscribe(todoList -> notifyDataSetChanged());
}
それ以外は?
ListViewではないレイアウトも世の中にはたくさんあります。React的に任意のレイアウトの描画コストを減らせる方法は、今のところ確立されていないように思います。
DataBindingってそれっぽい動きをしてくれないかしら・・・とは思いますが、未検証です。
まとめ
AndroidでReactの立場に立てるものってあるのかしら、と思索してみました。
双方向データバインディングを知ったときも人類を甘やかしてんなーと思ったものでしたが、Reactは更にその上をいく甘やかしっぷりです。人間を駄目にするライブラリです。そして私は駄目になりたい。
魂が震える記事から1年経ってしまったので、JS界隈からは1周遅れといった感じですが、どうにかキャッチアップしていきたいですね。