关于 ViewHolder 模式的点击问题,但不是 getView

On Click issue with ViewHolder pattern but not with getView

我正在将我的适配器代码从基本 getView() 模式更改为 ViewHolder 模式。我的适配器有一个 TextView、一个 ImageView 和一个 ImageButton。一切看起来都很好,但我在使用 ImageButton 时遇到了一些问题。我将 post 我的代码(一个 getView() 和另一个 ViewHolder)。 带有 getView() 的那个工作得很好,所以我在这里问是因为我不明白我在 ViewHolderImageButton.

中哪里做错了

适配器class with getView()

public class ListAdapter extends ArrayAdapter<Manga> {
    private final Context context;
    private List<Manga> list;
    DatabaseHandler dh;
    SQLiteDatabase db;
    ArrayList<MangaPreferito> mangaPrefAL;
    int current_id = 0;

    public ListAdapter(Context context, List<Manga> list) {
        super(context, R.layout.listadapter, list);

        this.context = context;
        this.list = list;
    }


    @Override
    public View getView(final int position, View rowView, ViewGroup parent) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        rowView = inflater.inflate(R.layout.listadapter, parent, false);

        dh = new DatabaseHandler(context);
        db = dh.getWritableDatabase();
        mangaPrefAL = dh.getAllPreferiti(db);

        TextView titolo = (TextView) rowView.findViewById(R.id.textView);
        ImageView immagine = (ImageView) rowView.findViewById(R.id.imageView);
        final ImageButton ibFavorite = (ImageButton) rowView.findViewById(R.id.imageView2);

        if (list.get(position).getFavorite()) {
            ibFavorite.setBackgroundResource(R.drawable.icon_star);
        } else {
            ibFavorite.setBackgroundResource(R.drawable.favorite_icon_no);
        }

        for (MangaPreferito m : mangaPrefAL) {
            if (list.get(position).getI().equals(m.getI())) {
                list.get(position).setFavorite(true);
            }
        }
        //HERE ONCLICK WORKS WELL

        ibFavorite.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                for (MangaPreferito m : mangaPrefAL) {
                    if (list.get(position).getI().equals(m.getI())) {
                        current_id = m.getId();
                    }
                }

                if (list.get(position).getFavorite()) {
                    list.get(position).setFavorite(false);
                    ibFavorite.setBackgroundResource(R.drawable.favorite_icon_no);
                    dh.deleteManga(current_id, db);
                } else {
                    list.get(position).setFavorite(true);
                    ibFavorite.setBackgroundResource(R.drawable.icon_star);
                    dh.addPreferito(new MangaPreferito(list.get(position).getA(),
                            Integer.parseInt(String.valueOf(list.get(position).getH())),
                            list.get(position).getI(),
                            list.get(position).getIm(),
                            Double.parseDouble(String.valueOf(list.get(position).getLd())),
                            Integer.parseInt(String.valueOf(list.get(position).getS())), list.get(position).getT()), db);

                }
            }
        });

        return rowView;
    }
}

Adapter class with ViewHolder

public class ListAdapter extends ArrayAdapter<Manga> {
    private final Context context;
    private List<Manga> list;
    DatabaseHandler dh;
    SQLiteDatabase db;
    ArrayList<MangaPreferito> mangaPrefAL;
    int current_id = 0;
    ViewHolder viewHolder;

    public ListAdapter(Context context, List<Manga> list) {
        super(context, R.layout.listadapter, list);

        this.context = context;
        this.list = list;
    }

    static class ViewHolder{
        TextView titolo;
        ImageView immagine;
        ImageButton ibFavorite;
    }

    @Override
    public View getView(final int position, View rowView, ViewGroup parent) {
        dh = new DatabaseHandler(context);
        db = dh.getWritableDatabase();
        mangaPrefAL = dh.getAllPreferiti(db);

        if(rowView==null){
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            rowView = inflater.inflate(R.layout.listadapter, parent, false);

            viewHolder = new ViewHolder();

            viewHolder.titolo = (TextView) rowView.findViewById(R.id.textView);
            viewHolder.immagine = (ImageView) rowView.findViewById(R.id.imageView);
            viewHolder.ibFavorite = (ImageButton)rowView.findViewById(R.id.imageView2);

            rowView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) rowView.getTag();
        }


        if(list.get(position).getFavorite()){
            viewHolder.ibFavorite.setBackgroundResource(R.drawable.icon_star);
        }else{
            viewHolder.ibFavorite.setBackgroundResource(R.drawable.favorite_icon_no);
        }

        for(MangaPreferito m : mangaPrefAL){
            if (list.get(position).getI().equals(m.getI())) {
                list.get(position).setFavorite(true);
            }
        }

        //HERE ONCLICK DOESN'T WORK

        viewHolder.ibFavorite.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                for(MangaPreferito m : mangaPrefAL){
                    if (list.get(position).getI().equals(m.getI())) {
                        current_id = m.getId();
                    }
                }

                if(list.get(position).getFavorite()){
                    list.get(position).setFavorite(false);
                    viewHolder.ibFavorite.setBackgroundResource(R.drawable.favorite_icon_no);
                    dh.deleteManga(current_id, db);
                }else{
                    list.get(position).setFavorite(true);
                    viewHolder.ibFavorite.setBackgroundResource(R.drawable.icon_star);
                    dh.addPreferito(new MangaPreferito(list.get(position).getA(),
                            Integer.parseInt(String.valueOf(list.get(position).getH())),
                            list.get(position).getI(),
                            list.get(position).getIm(),
                            Double.parseDouble(String.valueOf(list.get(position).getLd())),
                            Integer.parseInt(String.valueOf(list.get(position).getS())),list.get(position).getT()), db);

                }
            }
        });

        return rowView;
    }
}

如您所见,onClick() 中的代码是相同的,但 ViewHolder 中的代码不起作用,有人可以解释一下为什么吗? P.s。如果您需要更多代码或 classes 告诉我,我会编辑我的答案。

按照此策略正确使用具有视图持有者模式的点击侦听器:

  • 使您的 OnClickListener 成为 class 的成员,超出 getView(...) 调用的范围。这将确保您不会认为自己有闭包(因此您不再需要声明位置 final)。
  • 仅在 rowView==null 且视图被放大时设置您的点击侦听器,而不是在每次调用时设置。
  • 在您的点击处理程序中,对点击的视图调用 getTag 以访问 ViewHolder。您需要使用的一切都应该在视图持有者中。如果没有,请添加。

如果您需要,遵循此策略将为您转换为 RecyclerView 做好准备 - 也许现在是个好时机。