Adapterの使い方

前日、AdapterView(ListView/GridView/Gallery/Spinner)に対しての説明を行いました。
Adapterクラスは、データソースとビューのつなぎ役を果たすものです。
データの一覧を表示するには、上記挙げているViewにはsetAdapterメソッドがあり、 adapterがセットされると、表示すべきデータはこのアダプターから取得するようになります。

Adapterが内部データの違い(データがArrayだったり、Listだったり、Cursorだったりなど)を吸収してくれ るので、Viewは余計なことを考えずに描画に集中できるわけです。
アンドロイドのクラスライブラリで提供されている常に使うAdapterクラスは下記です

  • ArrayAdapter
  • SimpleAdapter
  • SimpleCursorAdapter

実作業中、上記の三つAdapterクラスを使うと、昨日の実現に対して難しいところもあるかもしれないので カスタマイズAdapterクラスの作成方法を下記に記述しておる

1.自分でAdapterクラスを実装する方法

  • 抽象クラス「BaseAdapter」から、子クラスを実装する実装するときに、下記の四つメソッドを実装しなければいけない

  • メソッド「getCount」は、Viewのアイテムの数、一般的に、渡されたデータオブジェクトの配列の長さを設定する。

  • ツール「MidSqlite」の実装クラス「MidTableRowAdapter」を例として説明する
1
2
3
4
@Override
public int getCount(){
  return row.getSize();
}

ここでは、データオブジェクトは、MidTableRowのオブジェクトとなるので、Rowのアイテム「列Column」を行としてListViewに並んで表示されている、この関数はRowの列数を戻る「row」はAdapterクラスのフィルドとして、コンストラクタで値を設定する

  • メソッド「getItem」は、データオブジェクトのアイテムを戻る。
      この関数は、一般的に④メソッド「getView」で呼び出して値を取得して表示することを行う
      下記の例では、rowのセルを戻る

    1
    2
    3
    4
    @Override
    public Object getItem(int position){
    return row.getCell(position);
    }
    
  • メソッド「getItemId」は、特にないです、普通はpositionを戻る

    1
    2
    3
    4
    @Override
    public long getItemId(int position){
    return position;
    }
    
  • メソッド「getView」
      Adapterはデータソースとビューのつなぎ役なので、表示すべきビューをデータソースから組み立てるのが仕事です。何- のデータをどのようなView構造で表示するか、それを決定するのがgetViewメソッドです。

    1
    2
    3
    @Override
    public View getView(final in position ,View convertView,final ViewGroup parent){
    }
    

positionは何要素目か、contentViewはposition番目のビューを、parentは親のビューグループです。

ListView,GridView,Galleryなど

普通の処理流れは、引数で受け取ったconvertViewをviewに受けて、nullチェックをしてnullならviewを生成し、nullでないならそれを使う、という流れになっています。
最後にviewをreturnで返しています。

下記の例で、ひとつアイテムで三つTextViewと一つEditTextを含める

レイアウトの定義は下記のように、

ListViewのアイテム(行)の構造を他のリソースファイルで定義する

この実装された「MidTableRowAdapter」の呼び出す例:

2.AdapterViewの特性

Viewの再利用

このgetViewメソッドは、新しいデータが表示されるタイミングで呼び出されます。
  スクロールして、画面外から新しいデータが表示されるタイミングです。
  こういった性質上、スクロールの度に何度も何度も呼び出されるため、getViewメソッドで無駄な処理があると、スクロールにひっかかりが出来るなど、パフォーマンスに直結した悪影響を及ぼします。
  AdapterViewの特性として、View(アイテム)の再利用という機能を用意できる
  "getViewで確認すべきところはしっかりViewを再利用しているかです。"
  getViewはこんなシグニチャになる

上記の例で、特性Viewの再利用は、イメージ通りです

特性検証   この特性は、Log機能を使ってDDMSでも確認できる。(コーディングは、下記のように修正する)

初めて、画面を表示するときに、かきのアイテムを構造する。

新しいアイテムを表示するときに、一番上の方で表示しないコントロールを使って 値を設定して表示する。新しいコントロールオブジェクトを生成しない。

3.AdapterViewの特性より、データの保存方法

上記の2の特性より、一目入力コントロールで入力されたデータを、下にスクロールして新しいの内容を表示するときに、失ってしまうとなる。

  • 内容を入力すると、Adapter設定のデータオブジェクトに変更しなければいけないです
  • タを表示するときに、データオブジェクト[row]からデータを取得して表示することを行なって 値を変更すると、[row]に書き込んで修正したら、今度その失ったアイテム(View)を再表示するときに、新しい値を取得できる。データも保存できる。

4.AdapterViewのデータの更新表示

ListViewなどをデータ[row]変更した場合は、下記のメソッドでViewの更新を行う

1
rowAdapter.notifyDataSetChanged();

2011/8/24:追記

5.子ビューへのアクセスを高速化

子ビューをアクセス時に、毎回ビューをリソースから引っ張りだしている所です。
Activityではこういったビュー要素はインスタンス変数へ格納して、
アクセスのショートカットをする、ここではgridViewなどのセルが多い場合では工夫が必要です。

1
2
3
4
textViewName=(TextView)view.findViewById(textViewResourceColumnName);
textViewType=(TextView)view.findViewById(textViewResourceColumnType);
textViewWidth=(TextView)view.findViewById(textViewResourceColumnWidth);
editTextRow=(EditText)view.findViewById(editTextResourceIdItem);

ここでは、ViewHolderというセル内の要素への参照を持つだけのクラスを用意することにする。

1
2
3
4
5
6
static class ViewHolder{
  TextView textViewName;
  TextView textViewType;
  TextView textViewWidth;
  EditText editTextRow;
}

このビューホルダーを使って、改善したコードが以下です。

ビューの再利用のために、nullチェックをするところは同じです。違うのは、ビューを初めて 作るタイミングでViewHolderをnewして、holderに子ビューであるTextViewやImageViewの参照をセットし、 それをview.setTag()でタグとして登録している所です。

これにより、再利用可能なビューが渡された時、view.getTag()として、子ビューへの参照を持った ViewHolderを取得できるようになります。

findViewByIdでviewを探す処理が省けるのでその分パフォーマンス改善が見込めます。


h1. 練習: 下記のイメージのクラスを自分で実現してください。