Removing Last Item From Android ListView Crashes The App

462 Views Asked by At

This is the error I am getting:

Process: com.painlessshopping.mohamed.findit, PID: 21324
    java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context android.view.ViewGroup.getContext()' on a null object reference
        at android.support.design.widget.Snackbar.<init>(Snackbar.java:192)
        at android.support.design.widget.Snackbar.make(Snackbar.java:224)
        at com.painlessshopping.mohamed.findit.CartAdapter$1.onClick(CartAdapter.java:100)
        at android.view.View.performClick(View.java:5201)
        at android.view.View$PerformClick.run(View.java:21163)
        at android.os.Handler.handleCallback(Handler.java:746)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:148)
        at android.app.ActivityThread.main(ActivityThread.java:5443)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)

And here is the code for my CartAdapter Class:

public class CartAdapter extends ArrayAdapter<Item> implements View.OnClickListener{

    private ArrayList<Item> dataSet;
    Context mContext;

    // View lookup cache
    private static class ViewHolder {
        TextView itemTitle;
        TextView itemStore;
        TextView itemPrice;
        ImageView storeLogo;
        ImageView removeFromCart;
    }

    public CartAdapter (ArrayList<Item> data, Context context) {
        super(context, R.layout.row_cart, data);
        this.dataSet = data;
        this.mContext=context;

    }

    @Override
    public void onClick(View v) {

        int position=(Integer) v.getTag();
        Object object= getItem(position);
        final Item item=(Item)object;

        CharSequence actions[];

        final View view = v;
        switch (v.getId())
        {

            case R.id.more:
                System.out.println(item.getLink());
                Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(item.getLink()));
                mContext.startActivity(browserIntent);
                break;
        }
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // Get the data item for this position
        final Item item = getItem(position);

        // Check if an existing view is being reused, otherwise inflate the view
        ViewHolder viewHolder; // view lookup cache stored in tag

        final View result;


            viewHolder = new ViewHolder();
            LayoutInflater inflater = LayoutInflater.from(getContext());
            convertView = inflater.inflate(R.layout.row_cart, parent, false);
            viewHolder.itemTitle = (TextView) convertView.findViewById(R.id.title);
            viewHolder.itemStore = (TextView) convertView.findViewById(R.id.retailer);
            viewHolder.itemPrice = (TextView) convertView.findViewById(R.id.price);
            viewHolder.storeLogo = (ImageView) convertView.findViewById(R.id.more);
            viewHolder.removeFromCart = (ImageView) convertView.findViewById(R.id.removeCart);

            result = convertView;

            convertView.setTag(viewHolder);

        viewHolder.itemTitle.setText(item.getTitle());
        viewHolder.itemStore.setText("From " + item.getStore());
        viewHolder.itemPrice.setText("$" + item.getPrice());
        viewHolder.storeLogo.setOnClickListener(this);

        viewHolder.removeFromCart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                CartInfoProvider.removeFromCart(item);
                MyCart.adapter.remove(item);
                MyCart.adapter.notifyDataSetChanged();

                Snackbar.make(result, "This item was removed from your cart", Snackbar.LENGTH_INDEFINITE).setAction("UNDO", new View.OnClickListener() {

                    @Override
                    public void onClick(View v) {
                        CartInfoProvider.addToCart(item);
                        MyCart.adapter.add(item);
                        MyCart.adapter.notifyDataSetChanged();
                    }

                }).show();

            }
        });


        viewHolder.storeLogo.setTag(position);

        // Return the completed view to render on screen
        return convertView;

    }
}

And here is the onCreate for my CartActivity:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_my_cart);

    ListView listView=(ListView)findViewById(R.id.cart);
    adapter= new CartAdapter(Items, this);
    listView.setAdapter(adapter);

    TextView empty = (TextView) findViewById(R.id.empty);
    listView.setEmptyView(empty);

    adapter.addAll(CartInfoProvider.getCart());
    adapter.notifyDataSetChanged();
}

The functionality works perfectly when there is more than 1 item in the cart. But when I try to remove the FINAL item from the cart, the app crashes and throws the above error. Any Ideas? I don't know what's wrong.

Edit: I'm assuming that someone's going to ask me to provide the code for CartInfoProvider so here it is:

public class CartInfoProvider {
    private static ArrayList<Item> cart = new ArrayList<Item>();

    public static void addToCart(Item i){
        cart.add(i);
    }

    public static void removeFromCart(Item i){
        cart.remove(i);
    }

    public static ArrayList<Item> getCart(){
        return cart;
    }
}
1

There are 1 best solutions below

0
On BEST ANSWER

As @CommonsWare said, I should've been using my listView instead of the actual row to display the snackbar. This is because when I remove the row the snackbar is trying to attach itself to something that doesn't exist, hence the nullpointer.

To fix this, I just changed the constructor of my adapter to read in the listview and then used that for my snackbar. Cheers!