Сбой приложения при удалении элемента из ListView при нажатии кнопки удаления

Мне очень трудно решить проблему с моим кодом.

При нажатии кнопки удаления в элементе ListView в идеале элемент должен быть удален, а представление списка должно быть обновлено при вызове notifyDataSetChanged();

Однако это не так: вызов этого метода после удаления элемента из базового ArrayList, который заполняет ListView, приводит к сбою приложения.

Кроме того, вышеупомянутый ArrayList, являющийся источником данных, существует в действии, которое расширяет приложение, обеспечивая глобальный доступ к источнику данных через приложение.

Ниже мой код. Любая помощь будет принята с благодарностью.

public class CartListAdapter extends ArrayAdapter<Product> {

    private ArrayList<Product> products;

    //Application context where ArrayList exists for globabal access
    final Global globalVariables = (Global) getContext().getApplicationContext();


    public CartListAdapter(Context context, int textViewResourceId, ArrayList<Product> products ) {
        super(context, textViewResourceId, products);

        this.products=products;
    }

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

        View row = convertView;
        prodHolder mainHolder;
         final int pos=position;
        if(row == null)
        {

            LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        row = inflater.inflate(R.layout.activity_cart_row_item, parent, false);
//create holders for listview items
        final prodHolder holder = new prodHolder();
            holder.txtName = (TextView) row.findViewById(R.id.cart_product_name);
            holder.txtAmount= (TextView) row.findViewById(R.id.cart_product_price);
            holder.txtQuantity=(TextView) row.findViewById(R.id.cart_quantity_text);
            holder.txtRestaurant= (TextView) row.findViewById(R.id.cart_restaurant);
            holder.txtType = (TextView) row.findViewById(R.id.cart_type);
            holder.txtOption  = (TextView) row.findViewById(R.id.cart_option);
            holder.plus = (Button) row.findViewById(R.id.cart_increment_quantity);
            holder.minus = (Button) row.findViewById(R.id.cart_decrement_quantity);
            holder.delete = (Button) row.findViewById(R.id.cart_delete_button);

            holder.delete.setOnClickListener(new View.OnClickListener() {

                @Override
                public void onClick(View v) {

                   globalVariables.getGlobalProductArrayList().remove(position);
                    CartListAdapter.this.notifyDataSetChanged();

                }
            });
//when clicking the plus button in the cart on an item, the cart changes accordingly
            holder.plus.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //change quantity when increment button pressed
                    String quantityTextValue= (String) holder.txtQuantity.getText();
                    int quantityConvertedInt = Integer.parseInt(quantityTextValue);
                    int newQuantity= quantityConvertedInt+1;
                    holder.txtQuantity.setText(newQuantity+"");
                    //change total amount when increment button pressed
                    String amountTextValue = (String) holder.txtAmount.getText();
                    int  amountConvertedInt = Integer.parseInt(amountTextValue);
                    int pricePerItem = amountConvertedInt/quantityConvertedInt;
                    int newPrice = amountConvertedInt+pricePerItem;
                    holder.txtAmount.setText(newPrice+"");

                    //get textviews from holders
                    Product product = new Product("", 0, 0, "", "", "");

                    String name = (String) holder.txtName.getText();
                    String price = (String) holder.txtAmount.getText();
                    String quantity = (String) holder.txtQuantity.getText();
                    String restaurant = (String) holder.txtRestaurant.getText();
                    String mealType = (String) holder.txtType.getText();
                    String option = (String) holder.txtOption.getText();
                    //set attributes of temporary product
                    product.setProductName(name);
                    product.setProductPrice(Integer.parseInt(price));
                    product.setProductQuantity(Integer.parseInt(quantity));
                    product.setRestaurant(restaurant);
                    product.setProductType(mealType);
                    product.setProductOption(option);

                    int cartLength = globalVariables.getMyProductsSize();

                    //loop through arraylist that exists in global context
                    for ( int i = 0; i < cartLength; i++) {
                        Product p = globalVariables.getMyProducts(i);

                        //if temporary product attributes match the attributes of product in arraylist

                        if (product.getProductName().equals(p.getProductName())
                                && product.getProductType().equals(p.getProductType())
                                && product.getProductOption().equals(p.getProductOption()))
                        //update that products attributes with the new quantity and total price so
                        // that listview does not refresh values
                        {
                            p.setProductQuantity(product.getProductQuantity());
                            p.setProductPrice(product.getProductPrice());
                        }

                    }

                }
            });


            row.setTag(holder);

        }

        mainHolder = (prodHolder) row.getTag();


        //get product stored in array that exists in Application class
        Product p = globalVariables.getMyProducts(position);


        mainHolder.txtName.setText(p.getProductName());
        mainHolder.txtAmount.setText(p.getProductPrice()+"");
        mainHolder.txtQuantity.setText(p.getProductQuantity()+"");
        mainHolder.txtRestaurant.setText(p.getRestaurant());
        mainHolder.txtType.setText(p.getProductType());
        mainHolder.txtOption.setText(p.getProductOption());

        return row;

    }

}

И глобальный класс, который расширяет ArrayList...

public class Global extends Application {


    //holds an array of products throughout application life cycle
    private ArrayList <Product> myProducts = new ArrayList<>();
    //not in use
    private Cart cart;


    public Cart getCart() {

        return cart;
    }

    public void setCart(Cart cart) {

        this.cart = cart;
    }


    public ArrayList <Product> getGlobalProductArrayList(){

        return this.myProducts;
    }

    public void removeItem (int position){

        myProducts.remove(position);
    }


//gets the products in the arraylist at the specified position
    public Product getMyProducts(int position) {
        return myProducts.get(position);
    }
//adds a product to the array
    public void addMyProducts(Product product) {
        myProducts.add(product);
    }
//get the size of the array, the amount of products in an array
    public int getMyProductsSize (){
        return myProducts.size();
    }

}

Трассировки стека...

01-29 23:40:13.992 28953-28953/za.co.clickandeat.clickeatbeta W/dalvikvm: threadid=1: thread exiting with uncaught exception (group=0x415c0d88)
01-29 23:40:13.992 28953-28953/za.co.clickandeat.clickeatbeta E/test: Exception
01-29 23:40:14.032 28953-28953/za.co.clickandeat.clickeatbeta E/AndroidRuntime: FATAL EXCEPTION: main 
Process: za.co.clickandeat.clickeatbeta, PID: 28953   java.lang.IndexOutOfBoundsException: Invalid index 1, size is 1
at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255) 
at java.util.ArrayList.get(ArrayList.java:308)
at za.co.clickandeat.clickeatbeta.Global.getMyProducts(Global.java:43) 
at za.co.clickandeat.clickeatbeta.CartListAdapter.getView(CartListAdapter.java:147)    at android.widget.AbsListView.obtainView(AbsListView.java:2240) 
at android.widget.ListView.measureHeightOfChildren(ListView.java:1263)  
at android.widget.ListView.onMeasure(ListView.java:1175)
at android.view.View.measure(View.java:16643)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5125)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1404)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:695)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:588)   
at android.view.View.measure(View.java:16643)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5125) 
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1404)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:695)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:588)
at android.view.View.measure(View.java:16643)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5125)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
at android.support.v7.internal.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:135)
at android.view.View.measure(View.java:16643)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5125)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1404)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:695)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:588)
at android.view.View.measure(View.java:16643)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5125)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
at android.view.View.measure(View.java:16643)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5125) 
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1404)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:695)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:588)
at android.view.View.measure(View.java:16643)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5125)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2298)
at android.view.View.measure(View.java:16643)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:1916)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1113)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1295)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1000)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5675)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761)
at android.view.Choreographer.doCallbacks(Choreographer.java:574)
at android.view.Choreographer.doFrame(Choreographer.java:544)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5214)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:814)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:630)
at dalvik.system.NativeStart.main(Native Method)

person R.Wyngaard    schedule 29.01.2016    source источник
comment
Вы уверены, что добавляете в список вашего глобального класса, а не только вашего адаптера?   -  person Cruceo    schedule 30.01.2016
comment
Добавление? Можете быть более конкретными?   -  person R.Wyngaard    schedule 30.01.2016
comment
Ошибка выдается в Global.getMyProducts(Global.java:43), пытаясь вызвать get(1), когда в вашем списке есть только 1 элемент. В вашем адаптере вы вызываете globalVariables.getMyProducts(position);, где вы обновили глобальные данные, но не данные, на которые фактически ссылается ваш адаптер, поэтому два списка не совпадают, вызывая IndexOutOfBoundsException. Изменение globalVariables.getMyProducts(position); to products.get(позиция); решит Исключение, но вам нужно убедиться, что ваш вызов удаления также удаляет элемент из списка, поддерживаемого вашим адаптером   -  person Cruceo    schedule 30.01.2016
comment
Это предложение несколько сработало. Приложение больше не падает, а представление списка обновляется. Однако теперь, когда я удаляю элемент из обоих списков, если элементов более 3, удаление самого последнего элемента в списке вместо этого удаляет первый элемент в представлении списка.   -  person R.Wyngaard    schedule 30.01.2016
comment
Это связано с тем, что список, на который опирается ваш адаптер, не синхронизирован с единственным экземпляром, хранящимся в вашем классе Application, что я и пытаюсь объяснить.   -  person Cruceo    schedule 01.02.2016


Ответы (1)


Вероятно, вам следует вызвать метод remove() на адаптере массива. Параметр — это объект Product, который вы хотите удалить.

Product product = globalVariables.getGlobalProductArrayList().get(position);
adapter.remove(product);

Такое удаление гарантирует, что адаптер знает об удаленном элементе и уведомляет себя о том, что что-то изменилось, тем самым обновляя все свойства адаптера.

person greenrobo    schedule 29.01.2016