android - ViewHolder单个onClick会影响多个列表项

时间:2015-09-09 12:16:24

标签: android listview android-viewholder

我正在使用带ViewHolder模式的自定义列表适配器将视图扩展到我的列表中,该列表显示图像(width = match_parent),左侧(图像下方)的一些文本和右侧的按钮(也在下方)图像)。

以下是适配器类的代码 -

public class DishItemListAdapter extends ArrayAdapter<DishItem> {

    //declare fonts - BOLD and LIGHT
    final Typeface tf_light = Typeface.createFromAsset(getContext().getAssets(),
            "fonts/Roboto-Thin.ttf");
    final Typeface tf_bold = Typeface.createFromAsset(getContext().getAssets(),
            "fonts/Roboto-Regular.ttf");

    //get item count
    CartItemCount cartItemCount;

    //count for dish at particular position
    ArrayList<Integer> dishCountList = new ArrayList<>();

    //for matching key string in SharedPrefs
    String existingKeyString;

    Typeface font_light, font_bold;
    /* List of DishItem Objects shown on the Dashboard */
    private List<DishItem> DishItemList = new ArrayList<DishItem>();

    public DishItemListAdapter(Context context, int textViewResourceId) {
        super(context, textViewResourceId);
        this.font_bold = tf_bold;
        this.font_light = tf_light;
    }

    /* Add a New DishItem Item (object) to the list of DishItems on the Dashboard i.e. DishItemList */
    @Override
    public void add(DishItem object) {
        DishItemList.add(object);
        super.add(object);
    }

    @Override
    public int getCount() {
        return this.DishItemList.size();
    }

    @Override
    public DishItem getItem(int index) {
        return this.DishItemList.get(index);
    }

    @Override
    public View getView(final int position, final View convertView, ViewGroup parent) {
        Log.e("getView() at " + position, "");
        View row = convertView;
        final DishItemViewHolder viewHolder;

        // A ViewHolder keeps references to children views to
        // avoid unnecessary (and expensive) calls to findViewById() on each row.
        if (row == null) {
            LayoutInflater inflater = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            row = inflater.inflate(R.layout.list_item_dish, parent, false);

            //instantiate DishItem View Holder
            viewHolder = new DishItemViewHolder();

            //get BUTTON for Adding Dish to Cart
            viewHolder.addToCart = (Button) row.findViewById(R.id.add_to_cart_button);

            //BUTTONS for + and - (adding and removing items from cart)
            viewHolder.addItemButton = (Button) row.findViewById(R.id.increase_item_count);
            viewHolder.removeItemButton = (Button) row.findViewById(R.id.decrease_item_count);

            //DISH NAME, CHEF NAME, DISH PRICE and DISH IMAGE
            viewHolder.dishName = (TextView) row.findViewById(R.id.dish_name_textview);
            viewHolder.chefName = (TextView) row.findViewById(R.id.chef_name_textview);
            viewHolder.dishPrice = (TextView) row.findViewById(R.id.dish_price_textview);
            viewHolder.dishImage = (ImageView) row.findViewById(R.id.dish_imageview);

            //image absolute path
            viewHolder.imageStorePath = new String();

            //image for depicting whether image is VEG or NON VEG
            viewHolder.veg_nonveg_indicator = (ImageView) row.findViewById(R.id.veg_nonveg_indicator);

            //viewSwitcher for switching between BUTTON and - + button
            viewHolder.viewSwitcher = (ViewSwitcher) row.findViewById(R.id.viewswitcher);

            //indicator for item added to Cart
            viewHolder.addedToCartIndicator = (TextView) row.findViewById(R.id.added_to_cart_text_indicator);
            viewHolder.addedToCartIndicator.setVisibility(View.INVISIBLE);

            //counter for number of items selected for a particular dish
            viewHolder.dishQuantity = (TextView) row.findViewById(R.id.dish_quantity);

            //set tag for the ViewHolder
            row.setTag(viewHolder);

        } else {
            /* Get the ViewHolder back to get fast access to the DishItem UI widgets (views) */
            viewHolder = (DishItemViewHolder) row.getTag();
        }

        //create object of Item Count Class
        cartItemCount = new CartItemCount();


        /* fetch DishItem View at current position (="position") */
        final DishItem dishItem = getItem(position);

        row.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e("clicked"+position,"");
                viewHolder.dishName.setText("CLICKED");
            }
        });
        return row;
    }

    static class DishItemViewHolder {
        TextView dishName;
        TextView chefName;
        TextView dishPrice;
        TextView dishQuantity;

        String imageStorePath;

        boolean isDishItemSelected;

        Button addToCart, addItemButton, removeItemButton;

        ImageView veg_nonveg_indicator;

        ImageView dishImage;

        ViewSwitcher viewSwitcher;

        TextView addedToCartIndicator;

    }
}

问题

假设我在列表中添加了6个DishItem bean(模型)。然后,当我对列表中的第一个项目执行onClick时,第一个项目的文本将更改为应该按下单击。此外,在日志中,在clicked:0中说(因为第一个列表项的索引是0)。

但是第4个列表项的文本也更改为CLICKED,它不应该。

现在我读了this帖子,解释了ListView的回收机制。

但是,我不希望它以这种方式工作,因为我只想更新我点击的那些项目。 我在这做错了什么? 这种回收机制是否有任何解决方法只更新我点击的特定项目?

更新

问题解决了。我遵循了BlackBelt的方法,因此接受了他的回答,但我要感谢你们所有人的投入! :)

这是更新的getView()方法。

 /**

*

* @param position The position of the item within the adapter's data set of the item whose view we want.

* @param convertView The old view to reuse, if possible.

* Note: You should check that this view is non-null and of an appropriate type before using.

* If it is not possible to convert this view to display the correct data, this method

* can create a new view. Heterogeneous lists can specify their number of view types,

* so that this View is always of the right type (see getViewTypeCount() and getItemViewType(int)).

* @param parent The parent that this view will eventually be attached to

* @return A View corresponding to the data at the specified position.

*/

    @Override

    public View getView(final int position, final View convertView, ViewGroup parent) {

        View row = convertView;

        final DishItemViewHolder viewHolder;


        // A ViewHolder keeps references to children views to

        // avoid unnecessary (and expensive) calls to findViewById() on each row.

        if (row == null) {

            LayoutInflater inflater = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);

            row = inflater.inflate(R.layout.list_item_dish, parent, false);


            //instantiate DishItem View Holder

            viewHolder = new DishItemViewHolder();


            //get BUTTON for Adding Dish to Cart

            //viewHolder.addToCart = (Button) row.findViewById(R.id.add_to_cart_button);

            viewHolder.addItemButton = (Button) row.findViewById(R.id.add_to_cart_secondary_button);

            viewHolder.removeItemButton = (Button) row.findViewById(R.id.remove_from_cart_button);


            //DISH NAME, CHEF NAME, DISH PRICE and DISH IMAGE

            viewHolder.dishName = (TextView) row.findViewById(R.id.dish_name_textview);

            viewHolder.chefName = (TextView) row.findViewById(R.id.chef_name_textview);

            viewHolder.dishPrice = (TextView) row.findViewById(R.id.dish_price_textview);

            viewHolder.dishImage = (ImageView) row.findViewById(R.id.dish_imageview);


            //image absolute path

            viewHolder.imageStorePath = new String();


            //image for depicting whether image is VEG or NON VEG

            viewHolder.veg_nonveg_indicator = (ImageView) row.findViewById(R.id.veg_nonveg_indicator);


            //indicator for item added to Cart

            viewHolder.addedToCartIndicator = (TextView) row.findViewById(R.id.added_to_cart_text_indicator);

            viewHolder.addedToCartIndicator.setVisibility(View.INVISIBLE);


            //set tag for the ViewHolder

            row.setTag(viewHolder);


        } else {

            /* Get the ViewHolder back to get fast access to the DishItem UI widgets (views) */

            viewHolder = (DishItemViewHolder) row.getTag();

        }


        //get object for CART ITEM COUNT class

        final CartItemCount cartItemCount = new CartItemCount();


        //get current dish item (MODEL from Bean class)

        final DishItem dishItem = getItem(position);


        //disable any highlighting unless dish is selected (verified from SharedPreferences)

        viewHolder.dishImage.setColorFilter(null);


        //hide ITEM COUNT indicator over the image unless dish is selected (again, verified from SharedPreferences)

        viewHolder.addedToCartIndicator.setVisibility(View.INVISIBLE);


        //show the + and - buttons on the right and left (respectively) side on the Dish ImageView

        viewHolder.addItemButton.setVisibility(View.VISIBLE);

        viewHolder.removeItemButton.setVisibility(View.VISIBLE);


        //get data from Preferences (to see which dish is selected)

        SharedPreferences pref = getContext().getSharedPreferences("DishDetails", Context.MODE_PRIVATE);

        Map<String, ?> allEntries = pref.getAll();

        for (Map.Entry<String, ?> entry : allEntries.entrySet()) {

            Log.d("KEY = " + entry.getKey(), " VALUE = " + entry.getValue().toString());

        }


        //get Count for each dish in the list and set Quantity in the Model (DishItem.java)

        if (pref != null) {

            int currentDishCount = pref.getInt("dishCount" + position, 0);

            Log.e("Current DishCount", String.valueOf(currentDishCount));

            if (currentDishCount > 0) {

                getItem(position).setisDishItemSelected(true);

                dishItem.setDishQuantity(currentDishCount);

                Log.d("dish item" + position," selected");

            }

        }


        //update Views for selected DishItems

        if (dishItem.isDishItemSelected()) {

            viewHolder.dishImage.setColorFilter(Color.parseColor("#80E0E0E0"));

            viewHolder.addedToCartIndicator.setVisibility(View.VISIBLE);

            viewHolder.addedToCartIndicator.setText(dishItem.getDishQuantity() + " items in cart");

        }


        viewHolder.addItemButton.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {

                dishItem.setisDishItemSelected(true);

                dishItem.setDishQuantity(dishItem.getDishQuantity() + 1);


                //save data to preferences

                SharedPreferences pref = getContext().getSharedPreferences("DishDetails", Context.MODE_PRIVATE);

                SharedPreferences.Editor editor = pref.edit();

                editor.putInt("dishCount" + position, dishItem.getDishQuantity());

                editor.commit();


                //increment Total Number of Items in Cart

                int itemCount = cartItemCount.getitemCount();

                cartItemCount.setitemCount(itemCount + 1);

                Log.d("itemCount =", String.valueOf(itemCount));

                //broadcast the value of itemCount to MainMenuActivity

                Intent intent = new Intent("NEW_CART_ITEM");

                intent.putExtra("value", cartItemCount.getitemCount());

                getContext().sendBroadcast(intent);

                Log.d("broadcast", "sent");


                //notify adapter of change in underlying data (i.e. update View to show Changes in Model)

                notifyDataSetChanged();



            }

        });



        viewHolder.removeItemButton.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {

                Log.d("Old Dish Qty. ", String.valueOf(dishItem.getDishQuantity()));

                //if dishCount has reached ZERO, set Dish as NOT SELECTED for buying

                if (dishItem.getDishQuantity() == 0) {

                    dishItem.setisDishItemSelected(false);


                } else {

                    dishItem.setisDishItemSelected(true);

                    dishItem.setDishQuantity(dishItem.getDishQuantity() - 1);

                    Log.d("New Dish Qty.", String.valueOf(dishItem.getDishQuantity()));


                    //decrement TOTAL number of items in Cart

                    int itemCount = cartItemCount.getitemCount();

                    cartItemCount.setitemCount(itemCount - 1);

                    Log.d("itemCount =", String.valueOf(itemCount));

                    //broadcast the value of itemCount to MainMenuActivity

                    Intent intent = new Intent("NEW_CART_ITEM");

                    intent.putExtra("value", cartItemCount.getitemCount());

                    getContext().sendBroadcast(intent);

                    Log.d("broadcast", "sent");


                    //recheck -> if dish Count has reached ZERO, set Dish as NOT SELECTED for buying

                    if (dishItem.getDishQuantity() == 0) {

                        dishItem.setisDishItemSelected(false);

                    }

                }


                //save Current Quantity of Dish Selected to SharedPreferences

                SharedPreferences pref = getContext().getSharedPreferences("DishDetails", Context.MODE_PRIVATE);

                SharedPreferences.Editor editor = pref.edit();

                editor.putInt("dishCount" + position, dishItem.getDishQuantity());

                editor.commit();


                //notify adapter of change in underlying data (i.e. update View to show Changes in Model)

                notifyDataSetChanged();

            }

        });


        return row;

    }

这个想法很简单(之前我不知道) -

  • 在按钮的onClick侦听器中,使用bean类中定义的setter和getter更改Model,即ie DishItem
  • 致电

    notifyDataSetChanged()

告诉适配器数据的变化,以便相应地调整视图。

  • 在getView()方法中,根据这些数据值设置视图。

2 个答案:

答案 0 :(得分:2)

  

这种回收机制是否有任何解决方法只能更新   我点击的特定项目?

这里没有解决方法。您必须更改数据集(位置 - 您单击的项目),并要求Adapter重绘ListView个孩子。我强烈建议你也使用OnItemClickListener

答案 1 :(得分:0)

您应该将视图的状态重置为getView中的默认状态,并在此之后应用项目的数据。它的工作原理如下:

  1. 获取行的视图(convertView或膨胀新视图)
  2. 创建并附加视图持有者
  3. 获取当前项目的数据和状态
  4. 应用所有状态参数和数据(如果单击当前项目则写入“Clicked”,否则清除TextView的文本 - 不要认为它已包含正确的文本)
  5. 您需要将项目的状态存储在某处 - 目前您使用TextView的文本执行此操作,并且由于回收行为而中断。正确的方法是向DishItem添加一个字段,或者只创建一个新类来包含每个项目的状态(选中,重点等等 - 您要支持的所有状态)。在onClickListener中更改状态的值,然后更改视图的内容,或者只需在适配器上调用notifyDataSetChanged