閉じる

データバインディングとビューの異常更新

データバインディングをガシガシ導入していたところ、どうにも動きがおかしい。

具体的には意図しないビューの更新が行われる。
しかも間違った内容で。
~Binding.java内の動きを追ってみると、funiの更新をかけたときに依存する barViewだけでなく fooViewのにも更新がかかることがわかった。
それだけなら問題ないようにみえるけど、内部的には
・更新された項目に関して内容を取得する(更新されていない内容に関しては再取得せずに null/0に設定される)
・依存する変数の更新
・依存するビューを更新
という風になっており、funiを取得して barViewは更新するけど、fooViewの更新に必要なデータの取得はされないので null/0で表示を更新している。
何故そうなるかとさらにコードを追ってみたところ…判明…_no

内部的に更新が必要な箇所をビットマップ*1 で保持しているのだけど、これの演算がおかしい。
bit20の変数が更新され、ソレを使った式の結果を bit41,42に格納するはずの所を bit9,10(41-32,42-32)に格納していますな。*2
どうやら、「変数と式の総数が 31以下という制限」もしくは「制限は 63以下*3 だけどバグで 31までしか動作しない」という事らしい。*4
自動生成のコードはいじれないので現状では前者の前提で書き直すしかない。*5
後者だとしても、ちょっと複雑なレイアウトを書いたら引っかかりそうだな。*6
いくら調べても同種の問題が報告されているのが見つからないというのはどうなんだろう?

MVVCを実践と言うところまでは行かなくても既に後戻りできないところまで来ているのでとっとと RCが取れて欲しいところ。<com.android.databinding.dataBinder
RC1になってから一ヶ月ほど経つけど動きがないのが気になる。
stackoverflowへの投稿によれば RC2がスタンバイしているようなんだけどね。

2015/09/11追記

公式の Issueにも上がってきたな<Possible dirtyFlags overflow when the number of bindings exceed 32
RC2での解決を試みるとかなってるね。

2015/09/16追記

1.0-RC2で「32個以上になった場合に誤動作する」点について修正されているのを確認。<データバインディング 1.0-RC2来た
64個以上になった場合についても対応されている模様。*7


*1 mDirtyFlags

*2 即値なのでコードのジェネレータがおかしい。

*3 64bit整数でビットマップを管理しているのでそうなると思うけど、やろうと思えば二つ以上の整数を使った管理も出来なくはないよな。

*4 com.android.databinding:dataBinder:1.0-rc1時点

*5 レイアウト自体を完全に分けるか、includeを使って誤魔化すか

*6 レイアウト自体はシンプルでも、ちょっと複雑な条件を書くとふくれあがる。

*7 内部的には予想通りフラグ変数を増やす泥臭い対応だけど、一般の開発者は直接触ることがない部分だし、速度的にはこれが一番有利だろうからいいんだろうね。

コメントを残す

メールアドレスが公開されることはありません。必須項目には印がついています *

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)