ティップスチップスと言うんじゃあない。Android先日、ArrayAdapterに対してadd()やclearなどの操作をしてもなぜか画面に反映されないという原因不明のバグを調査していたが、原因が判明したのでメモしておく。このバグはプログラミング初心者よりもむしろある程度経験を積んだ人ほどやってしまいそうなバグで、一見問題なさそうに見えるのでかなり厄介だと思う。ArrayAdapterをカスタマイズする時は絶対にこのバグを作りこまないように注意しましょう。まとめデータを自前で管理しない!結論から言うと、ArrayAdapterをカスタマイズする場合、絶対に自前でデータを管理してはならない。いうことかというと、ArrayAdapterをカスタマイズして独自のアダプタを作る際、アダプタのデータをメンバで管理してはならないということである。ダメなサンプルとして以下のSampleArrayAdapterクラスを示す。//ダメ、絶対!!!!}〜略〜}データを自前で管理するメリットは、データを操作したりカスタマイズしたアクセッサを簡単に実装できるなど色々考えられるが、アダプタにセットされるデータを自前で管理することは絶対にやってはいけない。このようなカスタムアダプタを作ってしまうと、アダプタに対してデータ操作を実行しても操作内容がリストに反映されないというバグが発生する。ArrayAdapterのコンストラクタを解剖ここで注目すべきなのはSampleArrayAdapterクラスのコンストラクタの中身である。SampleArrayAdapterのコンストラクタ内ではsuper=ArrayAdapterの引数が2つのコンストラクタが呼ばれている。ArrayAdapterのドキュメントを見ると、コンストラクタが5種類定義されている。ArrayAdapterをインスタンス化する時、通常よく使われるのはコンテキスト、レイアウトID、データ(配列かList)の3つの引数をとるコンストラクタである。data);これでdataの中身がアダプタにセットされて、画面表示とデータが適切に連携されるようになる。引数が2つのコンストラクタが呼ばれた場合、データには何がセットされるのだろうか。いうことでソースを確認してみる。ArrayAdapterのコンストラクタのソースは以下のようになっている。ArrayList<T>());}コンストラクタは内部でinit()というメソッドを呼んでいるだけのようである。他のコンストラクタも全て同じようになっている。このinitが何者なのか、ソースを見てみる。textViewResourceId;}initではコンストラクタに渡されたデータをメンバにセットしている。objects;である。mObjectsはアダプタにセットされるデータの実体である。アダプタに対する操作は、基本的にこのmObjectsに対して行われる。object)は以下のようになっている。notifyDataSetChanged();}mOriginalValuesはデータをフィルタリングした際に使用されるメンバなので、今回は関係ない。重要なのは、アダプタに対するadd呼び出しはmObjectsのaddを呼び出しているということである。これはinsertやclearなど他のメソッドでも同様である。mObjectsに適切なデータがセットされていなければアダプタに対する操作は全て無意味となる。適切なコンストラクタを使用するここまできたらようやくSampleArrayAdapterでなぜバグが発生するのかがわかってくる。SampleArrayAdapterのコンストラクタでは引数が2つのsuperのコンストラクタが使われていた。super(=ArrayAdapter)の引数が2つのコンストラクタを見てみよう。ArrayList<T>());}見ての通り、initの第4引数に空のリストを渡している。アダプタのデータには空のリストが設定される。SampleArrayAdapterのコンストラクタは引数が3つなので、このクラスを使うコードは以下のようになる。data);通常のArrayAdapterの呼び出しと何も変わらない。コンパイルエラーも起きないし、アダプタに対してaddやclearを行ってもエラーは発生しない(removeを行うとエラーになる可能性は高い)。実際にはコンストラクタに渡したデータはアダプタの内部構造と紐付いていないので、いくらアダプタに対してデータ操作をしても、それが画面に反映されることはない。SampleArrayAdapterのmDataの値を直接操作したところで、アダプタのデータとしてセットされていないのでこれも画面に反映されることはない。このように、呼び出し側としては通常通りにアダプタにデータをセットしているつもりだが、実際にはアダプタとデータの連携がとれておらず、しかも適切に操作を行えているように見えるという、非常に原因がわかりにくいバグが発生することになった。まとめ以上、長くなったが重要な点をまとめておく。先日AndroidStudioの1.5がリリースされたが、AndroidStudio1.5にしたら急にそれまでビルドできていたプロジェクトがビルドできないという現象が発生した。調べて見ると同じ現象...記事を読む[Mac]作業効率が劇的にアップするEclipseの必須キーボードショートカット15選そろそろAndroidの開発環境も徐々にAndroidStudioに移行してきているところも多いかと思いますが、実際の開発現場ではまだまだEclipseが主流派かと思います。ツールを移行する時...記事を読む[Android]ServiceのonRebindが呼ばれない原因と対策Androidで独自のServiceを実装する際、bindとunbindを繰り返すような実装を行わなければならないことがある。コメントをキャンセルメールアドレスが公開されることはありません。