Android Studio - 帮助我理解这段代码
Android Studio - Help me to understand this code
我正在尝试理解这段代码:
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
部分。
我的问题:
- 为什么我必须创建一个名为
ViewHolder
的 private class
只是创建一个 public method
来存储我所有的观点 (txtName,
txtSinger, playB, stopB
) 并在我的 inflater
? 中使用它
view.setTag(viewHolder)
是什么意思?
- 在这种情况下
setTag
和 getTag
到底是什么?
如果有人能为我分解它,那将对提高我对代码的理解非常有帮助。
谢谢。
What is exactly setTag and getTag in this context?
Android 视图支持 "tags",它们是您可以附加到它们的任意对象。标签没有真正的定义,因为它们是您想要的任何东西。所有这些都同样有效:
view.setTag(2)
view.setTag("Hello world")
view.setTag(new Object())
what does view.setTag(viewHolder) means?
您将 viewHolder
对象作为其标签附加到 view
。这本身 不做 任何事情,但它允许您稍后通过调用 (ViewHolder) view.getTag()
.
检索 viewHolder
Why do i have to create a private class called ViewHolder [...]
当您使用 ListView
适配器时,有两件事会降低应用程序的性能:调用 inflate()
和调用 findViewById()
.
您可以通过使用传入的 view
参数(当它不为空时)绕过第一个问题,并且仅在传入的 view
参数为空时调用 inflate()
。这就是您的代码:
if (view == null) {
...
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = layoutInflater.inflate(layout, null);
...
} else {
...
}
您可以使用此 "ViewHolder pattern" 绕过第二个。你创建一个 object (view holder) 到 "hold" views 在你查找它们之后。这就是您的代码:
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
的 ViewHolder
实例,您可以使用它直接访问视图。当传入的 view
参数为 null 时,您 创建 视图持有者,通过调用 findViewById()
填充 它,并通过调用 setTag()
保存。当传入的 view
参数不为 null 时,您可以通过调用 getTag()
.
简单地 检索 视图持有者
将它们放在一起,这意味着您可以编写如下代码:
viewHolder.txtName.setText(song.getName());
而不是这个较慢的代码:
TextView txtName = view.findViewById(R.id.songName_text);
txtName.setText(song.getName());
viewholder
是 android 应用中使用的一种设计模式,目的是取代更昂贵的 findviewbyid
调用。
引用文档
您的代码可能会在 ListView 滚动期间频繁调用 findViewById()
,这会降低性能。即使 Adapter returns 一个用于回收的膨胀视图,您仍然需要查找元素并更新它们。避免重复使用 findViewById()
的一种方法是使用 "view holder" 设计模式。
关于第二个和第三个问题,settag
和 gettag
基本上是让您的观点具有 "memories" 的一种方式,您可以参考 here 以获取更多信息和更详细的解释!
希望对您有所帮助!
我正在尝试理解这段代码:
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
部分。
我的问题:
- 为什么我必须创建一个名为
ViewHolder
的private class
只是创建一个public method
来存储我所有的观点 (txtName, txtSinger, playB, stopB
) 并在我的inflater
? 中使用它
view.setTag(viewHolder)
是什么意思?- 在这种情况下
setTag
和getTag
到底是什么?
如果有人能为我分解它,那将对提高我对代码的理解非常有帮助。
谢谢。
What is exactly setTag and getTag in this context?
Android 视图支持 "tags",它们是您可以附加到它们的任意对象。标签没有真正的定义,因为它们是您想要的任何东西。所有这些都同样有效:
view.setTag(2)
view.setTag("Hello world")
view.setTag(new Object())
what does view.setTag(viewHolder) means?
您将 viewHolder
对象作为其标签附加到 view
。这本身 不做 任何事情,但它允许您稍后通过调用 (ViewHolder) view.getTag()
.
viewHolder
Why do i have to create a private class called ViewHolder [...]
当您使用 ListView
适配器时,有两件事会降低应用程序的性能:调用 inflate()
和调用 findViewById()
.
您可以通过使用传入的 view
参数(当它不为空时)绕过第一个问题,并且仅在传入的 view
参数为空时调用 inflate()
。这就是您的代码:
if (view == null) { ... LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = layoutInflater.inflate(layout, null); ... } else { ... }
您可以使用此 "ViewHolder pattern" 绕过第二个。你创建一个 object (view holder) 到 "hold" views 在你查找它们之后。这就是您的代码:
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
的 ViewHolder
实例,您可以使用它直接访问视图。当传入的 view
参数为 null 时,您 创建 视图持有者,通过调用 findViewById()
填充 它,并通过调用 setTag()
保存。当传入的 view
参数不为 null 时,您可以通过调用 getTag()
.
将它们放在一起,这意味着您可以编写如下代码:
viewHolder.txtName.setText(song.getName());
而不是这个较慢的代码:
TextView txtName = view.findViewById(R.id.songName_text);
txtName.setText(song.getName());
viewholder
是 android 应用中使用的一种设计模式,目的是取代更昂贵的 findviewbyid
调用。
引用文档
您的代码可能会在 ListView 滚动期间频繁调用 findViewById()
,这会降低性能。即使 Adapter returns 一个用于回收的膨胀视图,您仍然需要查找元素并更新它们。避免重复使用 findViewById()
的一种方法是使用 "view holder" 设计模式。
关于第二个和第三个问题,settag
和 gettag
基本上是让您的观点具有 "memories" 的一种方式,您可以参考 here 以获取更多信息和更详细的解释!
希望对您有所帮助!