3

私は Android 開発に不慣れで、いくつかのサンプル コードを読んでいます。アダプター クラス (ArrayAdapter から派生) のサンプル コードから 1 つのメソッドをコピーしました。派生クラスには、テキスト ビューに加えてチェックボックスがあります。

@Override
public View getView(int position, View convertView, ViewGroup parent) {

  View listItem = super.getView(position, convertView, parent);

  CheckedTextView checkMark = null;
  ViewHolder holder = (ViewHolder) listItem.getTag();
  if (holder != null) {
    checkMark = holder.checkMark;
  } else {
    checkMark = (CheckedTextView) listItem.findViewById(android.R.id.text1);
    holder = new ViewHolder(checkMark);
    listItem.setTag(holder);
  }

  checkMark.setChecked(isInCollection(position));
  return listItem;
}

private class ViewHolder {
  protected final CheckedTextView checkMark;

  public ViewHolder(CheckedTextView checkMark) {
     this.checkMark = checkMark;
  }
}

サンプル コードは、ViewHolder オブジェクト内に View をキャッシュすることによって getView を最適化することです。

私が混乱しているのは、null でない場合は convertView が再利用され、View データがそこに取り込まれて返されると考えたことです。

この場合、コードで呼び出された setTag / getTag メソッドはどのように信頼できるのでしょうか? それが機能するためには、同じオブジェクトを取得する必要があるように思われますか?

4

2 に答える 2

5

おそらく、後続の呼び出しでgetTagから返されたビューは、別のリストアイテムに対するものであり、間違ったビューを返します。

アダプターはRecycleBinを使用します。このクラスを使用すると、ListViewは、画面に収まる数の行レイアウトと、スクロールおよびプリロード用の1つまたは2つの行レイアウトのみを作成できます。したがって、1000行のListViewと7行しか表示されない画面がある場合、ListViiewには8つの一意のビューしかない可能性があります。

上記の例を使用して質問します。これまでに作成されたのは、8つの行レイアウトと8つの後続のViewHolderのみです。ユーザーがスクロールしても、新しい行レイアウトは作成されません。行レイアウトの内容のみが変更されます。したがってgetTag()、適切なビューを参照する有効なViewHolderが常にあります。

(それは役に立ちますか?)

于 2013-01-21T22:54:03.320 に答える
5

あなたは正しい方向に進んでいます。ListViewsがどのように機能するかをより理解するのに役立つかもしれないいくつかの情報があります:

メソッドの単純な実装にgetView()は2つの目標があります。1つ目は、リストに表示されるビューを膨らませることです。2つ目は、表示する必要のあるデータをビューに入力することです。

あなたが述べたように、ListViewsはリストを構成するビューを再利用します。これは、ビューのリサイクルと呼ばれることもあります。この理由はスケーラビリティです。1000個のアイテムのデータを含むListViewについて考えてみます。ビューは多くのスペースを占める可能性があり、パフォーマンスの低下や恐ろしいことにつながる可能性があるため、1000ビューを膨らませてすべてをメモリに保持することは現実的ではありませんOutOfMemoryException。ListViewsを軽量に保つために、AndroidはこのgetView()メソッドを使用してViewsを基になるデータと結合します。ユーザーがリストを上下にスクロールすると、画面から移動したビューはすべてビューのプールに配置され、再利用されます。のconvertViewパラメータはgetView()このリストから取得されます。最初、このプールは空であるため、nullビューがに渡されgetView()ます。したがって、getViewの最初の部分は、次のことを確認する必要があります。convertView以前に膨らませました。convertViewさらに、すべてのリストアイテムに共通する属性を構成する必要があります。そのコードは次のようになります。

if(convertView == null)
{
    convertView = new TextView(context);
    convertView.setTextSize(28);
    convertView.setTextColor(R.color.black);  
}

の実装の2番目の部分ではgetView()、基になるデータソースでリストを確認し、ビューのこの特定のインスタンスを構成します。たとえば、テストリストに、ビューのテキストを設定するための文字列の配列があり、このビューのデータの現在の位置としてタグを設定したい場合があります。パーメーターに基づいて、リスト内のどのアイテムを処理しているかがpositionわかります。次に、この構成を行います。

String listText = myListStringsArray[position];
((TextView)convertView).setText(listText);
convertView.setTag(position);

これにより、新しいビューを膨らませたり作成したりするために費やす時間を最小限に抑えることができ、コストのかかる操作でありながら、各ビューを表示用にすばやく構成することができます。すべてをまとめると、メソッドは次のようになります。

@Override
public View getView(int position, View convertView, ViewGroup)
{ 
    if(convertView == null)
    {
        convertView = new TextView(context);
        //For more complex views, you may want to inflate this view from a layout file using a LayoutInflator, but I'm going to keep this example simple.

        //And now, configure your View, for example...
        convertView.setTextSize(28);
        convertView.setTextColor(R.color.black);  
    }

    //Configure the View for the item at 'position'
    String listText = myListStringsArray[position];
    ((TextView)convertView).setText(listText);
    convertView.setTag(position);

    //Finally, we'll return the view to be added to the list.

    return convertView;

}

ご覧のとおり、OSがViewHolderを処理するため、ViewHolderは必要ありません。ビュー自体は一時的なオブジェクトと見なす必要があり、ビューが保持する必要のある情報はすべて、基になるデータで管理する必要があります。

さらにもう1つの注意点として、OSは、プールに配置されるビューに対して何も実行しません。ビューに入力されたデータや変更が加えられた場合も含めて、ビューはそのままです。適切に実装されたgetView()メソッドは、基になるデータがビューの状態の変化を追跡することを保証します。たとえば、TextViewのテキストの色を赤のonClickに変更した場合、そのビューがリサイクルされると、テキストの色は赤のままになります。この場合、テキストの色はいくつかの基礎となるデータにリンクされ、呼び出されるif(convertView == null)たびに条件の外側に設定する必要があります。getView()(基本的に、すべてのconvertViewに共通の静的セットアップは、現在のリストアイテムに基づく条件付きの動的セットアップ内で行われ、ユーザー入力は後で行われます)これがお役に立てば幸いです。

編集済み-例をより単純にし、コードをクリーンアップしました。Samに感謝します。

于 2013-01-21T22:54:17.397 に答える