我正在尝试理解以下代码:
private class ViewHolder {
TextView txtName, txtSinger;
ImageView playB, stopB;
}
@Override
public View getView(int position, View view, ViewGroup parent) {
final ViewHolder viewHolder;
if (view == null) {
viewHolder = new ViewHolder();
// inflate (create) another copy of our custom layout
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = layoutInflater.inflate(layout, null);
viewHolder.txtName = (TextView) view.findViewById(R.id.songName_text);
viewHolder.txtSinger = (TextView) view.findViewById(R.id.singer_text);
viewHolder.playB = (ImageView) view.findViewById(R.id.play_png);
viewHolder.stopB = (ImageView) view.findViewById(R.id.stop_png);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
final Song song = arrayList.get(position);
// make changes to our custom layout and its subviews
viewHolder.txtName.setText(song.getName());
viewHolder.txtSinger.setText(song.getSinger());
// play music
viewHolder.playB.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// MediaPlayer has not been initialized OR clicked song is not the currently loaded song
if (currentSong == null || song != currentSong) {
// Sets the currently loaded song
currentSong = song;
mediaPlayer = MediaPlayer.create(context, song.getSong());
Toast.makeText(context, "Playing: "+ song.getSinger() + " " + song.getName(), Toast.LENGTH_LONG).show();
}
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
viewHolder.playB.setImageResource(R.drawable.play);
} else {
mediaPlayer.start();
viewHolder.playB.setImageResource(R.drawable.pause);
}
}
});
// stop
viewHolder.stopB.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// If currently loaded song is set the MediaPlayer must be initialized
if (currentSong != null) {
mediaPlayer.stop();
mediaPlayer.release();
currentSong = null; // Set back currently loaded song
}
viewHolder.playB.setImageResource(R.drawable.play);
}
});
return view;
}
但不是整个代码!
使我感到困惑的部分是ViewHolder
部分。
我的问题:
private class
的{{1}}
仅创建一个ViewHolder
来存储我所有的视图(public method
)并将其用于我的txtName,
txtSinger, playB, stopB
的想法?inflater
是什么意思?view.setTag(viewHolder)
和setTag
到底是什么?如果有人可以帮我解决这个问题,那么对我对代码的理解将非常有帮助。
谢谢。
答案 0 :(得分:1)
在这种情况下,setTag和getTag到底是什么?
Android视图支持“标签”,它们是可以附加到它们的任意对象。标签没有真正的定义,因为它们就是您想要的它们。所有这些都同样有效:
view.setTag(2)
view.setTag("Hello world")
view.setTag(new Object())
view.setTag(viewHolder)是什么意思?
您正在将viewHolder
对象作为其标签附加到view
。这本身并不能执行任何操作,但是可以让您稍后调用viewHolder
来检索(ViewHolder) view.getTag()
。
我为什么必须创建一个名为ViewHolder的私有类[...]
使用ListView
适配器时,有两件事会降低应用程序的性能:调用inflate()
和调用findViewById()
。
您可以通过使用传入的view
参数(不为null)来绕过第一个参数,而仅当传入的inflate()
参数为null时才调用view
。这就是您的代码:
if (view == null) { ... LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = layoutInflater.inflate(layout, null); ... } else { ... }
使用此“ ViewHolder模式”可以绕过第二个。创建对象(视图持有者)以在查找视图后“保留”视图。这就是您的代码:
final ViewHolder viewHolder; if (view == null) { viewHolder = new ViewHolder(); ... viewHolder.txtName = (TextView) view.findViewById(R.id.songName_text); viewHolder.txtSinger = (TextView) view.findViewById(R.id.singer_text); viewHolder.playB = (ImageView) view.findViewById(R.id.play_png); viewHolder.stopB = (ImageView) view.findViewById(R.id.stop_png); view.setTag(viewHolder); } else { viewHolder = (ViewHolder) view.getTag(); }
完成该块后,您将拥有一个名为ViewHolder
的{{1}}实例,可用于直接访问视图。当传入的viewHolder
参数为空时,您创建视图持有者,通过调用view
填充它,并保存< / em>,方法是调用findViewById()
。如果传入的setTag()
参数不为null,则可以通过调用view
来检索视图持有者。
将它们放在一起,这意味着您可以编写如下代码:
getTag()
代替此较慢的代码:
viewHolder.txtName.setText(song.getName());
答案 1 :(得分:1)
viewholder
是一种在Android应用中使用的设计模式,用于替换更昂贵的findviewbyid
调用。
引用文档
在滚动ListView时,您的代码可能会频繁调用findViewById()
,这可能会降低性能。即使适配器返回膨胀视图以进行回收,您仍然需要查找元素并进行更新。重复使用findViewById()
的一种方法是使用“视图持有人”设计模式。
关于第二个和第三个问题,settag
和gettag
基本上是您的观点具有“记忆力”的一种方式,您可以参考here以获得更多信息和更详细的解释!
希望这会有所帮助!