View
型オブジェクトのsetTag()
やgetTag()
のようなメソッドの主な目的は何ですか?
1つのビューに任意の数のオブジェクトを関連付けることができると私は考えていますか?
似たようなたくさんのビューを生成したとしましょう。各ビューにOnClickListener
を個別に設定できます。
button1.setOnClickListener(new OnClickListener ... );
button2.setOnClickListener(new OnClickListener ... );
...
それから、たとえそれらが同じようなことをしても、あなたはそれぞれのビューのためにユニークなonClick
メソッドを作らなければなりません:
public void onClick(View v) {
doAction(1); // 1 for button1, 2 for button2, etc.
}
これはonClick
がView
というパラメータを1つだけ持ち、それを囲むスコープ内のインスタンス変数または最後のローカル変数から他の情報を取得する必要があるためです。私たちが本当に欲しいのは、ビュー自体から情報を取得することです。
getTag
/setTag
を入力します。
button1.setTag(1);
button2.setTag(2);
これで、すべてのボタンに同じOnClickListenerを使用できます。
listener = new OnClickListener() {
@Override
public void onClick(View v) {
doAction(v.getTag());
}
};
基本的にはビューが記憶を持つ方法です。
少し言葉を加えたいのですが。
get/setTag(Object)
を使うことはViewHolderパターンの特定のケースで非常に役に立つようですが、私は他のケースでそれを使う前に二度考えることをお勧めします。ほとんどの場合、別の優れた設計ソリューションがあります。
主な理由は、コードがすぐにサポート不可能になることです。
他の開発者にとって、ビュー内のタグとして格納するように設計したものは明らかではありません。メソッドsetTag/getTagはまったく説明的ではありません。
Object
を格納するだけなので、getTag
にしたいときはキャストが必要です。タグに格納されているオブジェクトの種類を変更すると、後で予期しないクラッシュが発生する可能性があります。
これは実生活からの物語です。たくさんのアダプタ、ビューを使った非同期操作など、かなり大きなプロジェクトがありました。ある開発者は自分のコードの一部にset/getTag
を入れることにしましたが、別の開発者はすでにこのビューにタグを設定しました。結局、誰かが自分のタグを見つけることができず、非常に混乱しました。そのため、バグを見つけるのに数時間かかりました。
setTag(int key, Object tag)
はずっと良く見えるので、( idリソース を使用して)すべてのタグに対して一意のキーを生成できますが、Android <4.0では大きな制限があります。 Lintのドキュメントから:
Android 4.0より前のバージョンでは、View.setTag(int、Object)の実装では、値が強く参照される静的マップにオブジェクトを格納していました。つまり、そのオブジェクトにコンテキストを指す参照が含まれていると、コンテキスト(それ以外のほとんどすべてのものを指す)がリークすることになります。ビューを渡すと、そのビューはそれを作成したコンテキストへの参照を提供します。同様に、ビューホルダーには通常ビューが含まれており、カーソルもビューに関連付けられていることがあります。
setTag()
とgetTag()
を使用して、要件に従ってカスタムオブジェクトを設定および取得できます。 setTag()
メソッドはObject
型の引数を取り、getTag()
はObject
を返します。
例えば、
Person p = new Person();
p.setName("Ramkailash");
p.setId(2000001);
button1.setTag(p);
Web開発者にとって、これはdata- ..と同等のようです。
これはカスタムのArrayAdapter
を使うのにとても便利です。それはある種の最適化です。 setTag
は、ListView
の代わりに(findViewById
で表示される)レイアウトのいくつかの部分を参照するオブジェクトへの参照として使用されます。
static class ViewHolder {
TextView tvPost;
TextView tvDate;
ImageView thumb;
}
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater = myContext.getLayoutInflater();
convertView = inflater.inflate(R.layout.postitem, null);
ViewHolder vh = new ViewHolder();
vh.tvPost = (TextView)convertView.findViewById(R.id.postTitleLabel);
vh.tvDate = (TextView)convertView.findViewById(R.id.postDateLabel);
vh.thumb = (ImageView)convertView.findViewById(R.id.postThumb);
convertView.setTag(vh);
}
....................
}
IDとは異なり、タグはビューの識別には使用されません。タグは基本的に、ビューに関連付けることができる追加の情報です。それらは、ビューに関連するデータを別の構造に入れるのではなく、ビュー自体に格納するための便利な方法として最もよく使用されます。
参照: http://developer.Android.com/reference/Android/view/View.html
TAGの設定は、ListViewを持っていてビューをリサイクル/再利用したい場合に本当に便利です。そのようにして、ListViewは新しいRecyclerViewと非常によく似ています。
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
ViewHolder holder = null;
if ( convertView == null )
{
/* There is no view at this position, we create a new one.
In this case by inflating an xml layout */
convertView = mInflater.inflate(R.layout.listview_item, null);
holder = new ViewHolder();
holder.toggleOk = (ToggleButton) convertView.findViewById( R.id.togOk );
convertView.setTag (holder);
}
else
{
/* We recycle a View that already exists */
holder = (ViewHolder) convertView.getTag ();
}
// Once we have a reference to the View we are returning, we set its values.
// Here is where you should set the ToggleButton value for this item!!!
holder.toggleOk.setChecked( mToggles.get( position ) );
return convertView;
}