Search code examples
androidfirebase-realtime-databaseandroid-recyclerviewfirebase-storageandroid-alertdialog

Delete Item from Firebase in Recycler View when using Alert Dialog Box


I retrieved item records to the recycler view using the Firebase database and storage and implemented public void onDeleteClick(int position) to delete the selected item. And added a custom alert box to confirm the deletion. It is pretty working without Alert Dialog when just clicked delete. But when I choose "No" from Dialog It cannot be deleted again and shows the following error.

Can you help me to solve this issue.

E/StorageException: StorageException has occurred.
    Object does not exist at location.
     Code: -13010 HttpResult: 404
E/StorageException: {  "error": {    "code": 404,    "message": "Not Found.  Could not delete object",    "status": "DELETE_OBJECT"  }}
    java.io.IOException: {  "error": {    "code": 404,    "message": "Not Found.  Could not delete object",    "status": "DELETE_OBJECT"  }}
        at com.google.firebase.storage.network.NetworkRequest.parseResponse(NetworkRequest.java:445)
        at com.google.firebase.storage.network.NetworkRequest.parseErrorResponse(NetworkRequest.java:462)
        at com.google.firebase.storage.network.NetworkRequest.processResponseStream(NetworkRequest.java:453)
        at com.google.firebase.storage.network.NetworkRequest.performRequest(NetworkRequest.java:272)

Here is the code

@Override
    public void onDeleteClick(int position) {

        Upload selectedItem = mUploads.get(position);
        StorageReference imageRef = mStorage.getReferenceFromUrl(selectedItem.getmImageUrl());

        imageRef.delete().addOnSuccessListener(new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void aVoid) {

                View view = LayoutInflater.from(ShowPatientsRecords.this).inflate(R.layout.alertdelete, null);

                Button no = view.findViewById(R.id.dltNo);
                Button yes = view.findViewById(R.id.dltYes);

                AlertDialog dialog = new AlertDialog.Builder(ShowPatientsRecords.this).setView(view).create();
                dialog.setCancelable(false);
                dialog.show();

                yes.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {

                        Upload selectedItem = mUploads.get(position);
                        final String selectedKey = selectedItem.getmKey();

                        mDatabaseRef.child(selectedKey).removeValue();  **//This line is not working after No click in the Alert Dialog**
                        dialog.dismiss();
                        Toast.makeText(ShowPatientsRecords.this, "Record deleted", Toast.LENGTH_LONG).show();
                    }
                });

                no.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        dialog.dismiss();
                    }
                });
            }
        });
    }

Adapter Class

 @Override
    public int getItemCount() {
        return mUploads.size();
    }

    public class ImageViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener,
            View.OnCreateContextMenuListener,
            MenuItem.OnMenuItemClickListener{

        public TextView recDate;
        public TextView recDes;
        public TextView recDoc;
        public ImageView imageView;

        public ImageViewHolder(@NonNull View itemView) {
            super(itemView);

            recDate = itemView.findViewById(R.id.showdate);
            recDes = itemView.findViewById(R.id.showdescription);
            recDoc = itemView.findViewById(R.id.showdoc);
            imageView = itemView.findViewById(R.id.showImage);

            itemView.setOnClickListener(this);
            itemView.setOnCreateContextMenuListener(this);
        }

        @Override
        public void onClick(View v) {
            if (mListener != null) {
                int position = getAdapterPosition();

                if (position != RecyclerView.NO_POSITION) {
                    mListener.onItemClick(position);
                }
            }
        }

        @Override
        public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
            menu.setHeaderTitle("Select Action");
            MenuItem delete = menu.add(Menu.NONE, 1, 1, "Delete");
            delete.setOnMenuItemClickListener(this);
        }

        @Override
        public boolean onMenuItemClick(MenuItem item) {
            if (mListener != null) {
                int position = getAdapterPosition();
                if (position != RecyclerView.NO_POSITION) {
                    switch (item.getItemId()) {
                        case 1:
                            mListener.onDeleteClick(position);
                            return true;
                    }
                }
            }
            return false;
        }
    }

    public interface OnItemClickListener {
        void onItemClick(int position);
        void onDeleteClick(int position);
    }
    public void setOnItemClickListener(OnItemClickListener listener) {
        mListener = listener;
    }
}

Solution

  • The problem is that you delete the file from Firebase Storage before you ever show the alert box that asks the user to confirm. The flow is:

    1. The user clicks the Delete button.
    2. Your onDeleteClick finds the file for the image URL.
    3. Your onDeleteClick deletes the file.
    4. Your onDeleteClick asks the user to confirm they want to delete the file.
    5. If the user says "Yes", your onDeleteClick delete the reference to the file from the database.

    From the above it's clear that you delete the file too early in your code. If the user clicks "No" in step 5, and clicks the Delete button again, the error comes from step 2 as the file is already gone.

    The solution is to ask for confirmation before deleting the file:

    @Override
    public void onDeleteClick(int position) {
        Upload selectedItem = mUploads.get(position);
        StorageReference imageRef = mStorage.getReferenceFromUrl(selectedItem.getmImageUrl());
    
            View view = LayoutInflater.from(ShowPatientsRecords.this).inflate(R.layout.alertdelete, null);
    
            Button no = view.findViewById(R.id.dltNo);
            Button yes = view.findViewById(R.id.dltYes);
    
            AlertDialog dialog = new AlertDialog.Builder(ShowPatientsRecords.this).setView(view).create();
            dialog.setCancelable(false);
            dialog.show();
    
            yes.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Upload selectedItem = mUploads.get(position);
                    final String selectedKey = selectedItem.getmKey();
    
                    imageRef.delete().addOnSuccessListener(new OnSuccessListener<Void>() {
                        @Override
                        public void onSuccess(Void aVoid) {
                            mDatabaseRef.child(selectedKey).removeValue();
                            dialog.dismiss();
                            Toast.makeText(ShowPatientsRecords.this, "Record deleted", Toast.LENGTH_LONG).show();
                        }
                    });
                }
            });
    
            no.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    dialog.dismiss();
                }
            });
        }
    }