Giorgio Antonioli
Giorgio Antonioli

Reputation: 16224

On Click issue with ViewHolder pattern but not with getView

I'm changing my adapter code from the basic getView() to ViewHolder pattern. My adapter has one TextView, one ImageView and one ImageButton. Everything looks fine but i'm having some problems with the ImageButton. I'll post both my code (the one with getView() and the other with ViewHolder). The one with getView() works perfectly, so i'm asking here cause i can't understand where i'm doing wrong in the ViewHolder's ImageButton.

Adapter 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;
    }
}

As you can see the code inside onClick() is the same but with ViewHolder it doesn't work, can someone explain me why? P.s. If you need more code or classes tell me and i'll edit my answer.

Upvotes: 1

Views: 956

Answers (1)

Greg Ennis
Greg Ennis

Reputation: 15379

Follow this strategy to properly use click listeners with the view holder pattern:

  • Make your OnClickListener a member of your class, outside the scope of the getView(...) call. This will ensure you dont have problems with thinking you have closures (so you dont need position to be declared final anymore).
  • Set your click listener only when rowView==null and the view is inflated, not on every call.
  • In your click handler, call getTag on the view clicked to access the ViewHolder. Everything you need to use should be in the view holder. If not, add it.

Follow this strategy will well prepare you to convert to RecyclerView if you ever need to - maybe now would be a good time.

Upvotes: 4

Related Questions