首页 > 解决方案 > Android Studio - 帮助我理解这段代码

问题描述

我试图理解这段代码:

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部分。

我的问题:

如果有人可以为我分解这一点,那将有助于我对代码的理解。

谢谢你。

标签: javaandroidandroid-studiolayout-inflaterandroid-viewholder

解决方案


在这种情况下,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,并且仅inflate()在传入的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名为的实例viewHolder,您可以使用该实例直接访问视图。当传入的view参数为 null 时,您创建视图持有者,通过调用填充findViewById(),并通过调用保存setTag()。当传入的view参数不为空时,您可以通过调用简单地检索视图持有者getTag()

将所有这些放在一起,这意味着您可以编写如下代码:

viewHolder.txtName.setText(song.getName());

而不是这个较慢的代码:

TextView txtName = view.findViewById(R.id.songName_text);
txtName.setText(song.getName());

推荐阅读