0

I have implemented Firebase Database and can successfully add items to it and then display them on a RecyclerView. I also managed to implement Deletion of a child of a database which is successful BUT I need to restart activity to see changes on my phone's screen. For example: when I press Delete on my list item, it disappears from Database instantly but I need to restart the activity to see the change. Here is my code snippets:

 private void attachDatabaseReadListener() {

    queryRef.addChildEventListener(new ChildEventListener() {
        @Override
        public void onChildAdded(DataSnapshot dataSnapshot, String s) {
            locationCurrent = dataSnapshot.getValue(LocationCurrent.class);
            locationCurrent.setRefKey(dataSnapshot.getKey());
            mLocationAdapter.add(locationCurrent);

        }

        @Override
        public void onChildChanged(DataSnapshot dataSnapshot, String s) {
            locationCurrent = dataSnapshot.getValue(LocationCurrent.class);


        }

        @Override
        public void onChildRemoved(DataSnapshot dataSnapshot) {

        }

        @Override
        public void onChildMoved(DataSnapshot dataSnapshot, String s) {

        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });

}

I believe I should work on onChildRemoved but have no idea where to start. My main Idea was to repopulate recyclerview using for loop but locationCurrent object I got from datasnapshot is null.

Any ideas where should I start looking for solution? I have also considered to run addValueEventListener method on my query but I run into the problem where I get multiple copies of my single child

UPDATE Referring to some comments here is my adapter

public class LocationAdapter extends ArrayAdapter<LocationCurrent> {



public LocationAdapter(Context context, int resource, List<LocationCurrent> objects) {
    super(context, resource, objects);
}

@NonNull
@Override
public View getView(int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        convertView = ((Activity) getContext()).getLayoutInflater().inflate(R.layout.item_location, parent, false);
    }

    LocationCurrent currentLocation = getItem(position);

    TextView nameTextView = (TextView) convertView.findViewById(R.id.nameTextView);

    TextView descriptionTextView = (TextView) convertView.findViewById(R.id.descriptionTextView);


    nameTextView.setText(currentLocation.getName());
    descriptionTextView.setText(currentLocation.getDescription());



    return convertView;
}

}

By the way - my Ref Key which is used in locationCurrent class is transient variable and thus not visible in Database.

UPDATE2

After all day of working, I still did not manage to get the item off the adapter as soon it is deleted. Instead - I came up with a temporary solution - I added a recreate() method inside my onChildRemoved and it does it's job. (Not a good practice but still - something)

  • You will need to find the position of `dataSnapshot` in your `mLocationAdapter` and then remove it from the adapter. How to do that depends on your adapter implementation. But given that you already put the snapshot's key into the `LocationCurrent` object, it should be a fairly straightforward lookup. – Frank van Puffelen Jan 20 '17 at 21:17
  • Thank you didn't think I have to do it that way. Am I right saying that everything is done inside `onChildRemoved` and `DataSnapshot` inside that method is the snapshot of the Item I delete? –  Jan 20 '17 at 21:27
  • Yup. That's indeed the way of dealing with it. Keep in mind that [FirebaseUI-Android](https://github.com/firebase/FirebaseUI-Android/tree/master/database) has some ready-made adapters that already do all of this. You could use those or at least use them for (copy/paste) inspiration. – Frank van Puffelen Jan 20 '17 at 21:44
  • Thank you. I was just curious why simple `mLocationAdapter.remove(locationCurrent);` does not work? because snapshot returns an object I am deleting and with that line of code I am choosing a locationCurrent object which will get deleted from a adapter. –  Jan 20 '17 at 21:56
  • @martynaskuc not really sure why, but then again its best to delete the location directly by its key. In this way, you know that you're referring to the exact same thing on the firebase database. – Nicholas Jan 20 '17 at 23:12

1 Answers1

1

Basically, this is how I did a removal method.

            /**
             * This removes the CardView from the RecyclerView, allowing us to create a delete request
             *
             * http://stackoverflow.com/questions/27293960/swipe-to-dismiss-for-recyclerview/30601554#30601554
             *
             * @param viewHolder
             * @param direction
             */
            @Override
            public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
                // First find the position of the card
                // https://www.learn2crack.com/2016/02/custom-swipe-recyclerview.html
                int position = viewHolder.getAdapterPosition();

                // Connect to the database, identify which card was swiped via the RecyclerViewAdapter
                DatabaseReference currRef = adapter.getRef(position);

                // Get it out of the DB
                currRef.removeValue();
            }

The following code above should give you a rough idea of the deletion process. You need to retrieve the index of the element you want to remove. In your context, your location key be binded somehow.

Just FYI, here's the populateViewHolder based a FirebaseRecyclerAdapter.

                    /**
                     * Populating the RecyclerView..
                     *
                     * @param viewHolder
                     *
                     *
                     * @param task
                     *
                     *
                     * @param position
                     * With the use of position, we can obtain the key of from the FirebaseDatabase
                     *
                     * http://stackoverflow.com/questions/37568703/how-to-get-keys-and-values-using-firebaselistadapter
                     */
                    @Override
                    protected void populateViewHolder(TaskViewHolder viewHolder, Tasks task, int position) {
                        // Get the key of the Tasks object
                        //String currentKey = getRef(position).push().getKey();
                        //final String currentKey = getRef(position).toString(); // This returns the object URL from Firebase
                        final String currentKey = getRef(position).getKey();
                        Log.d(TAG, currentKey.toString());
                        Log.d(TAG, "Image: " + task.getImageUrl());

                        // Perform some DateTime formatting from the ISO8601 format

                        // Basically we need to attach the task to the viewHolder so that
                        // the cards can instantiate their view properly
                        viewHolder.setTaskName(task.getTaskName());
                        viewHolder.setTaskDesc(task.getTaskDescription());
                        viewHolder.setTaskDate(task.getTaskDeadline());
                        viewHolder.setTaskImage(task.getImageUrl());

                        final Intent updateView = new Intent(getActivity(), UpdateTaskActivity.class);

                        // Implement Serializable on the Tasks object,
                        // Push the object directly via updateView.putExtra
                        // That way we can have everything we need in the object.

                        //updateView.putExtra("TaskName", task.getTaskName());
                        //updateView.putExtra("TaskDesc", task.getTaskDescription());
                        updateView.putExtra("TaskObject", task);
                        updateView.putExtra("Key", currentKey);

                        viewHolder.mView.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                /**
                                 * How to provide a foundation to animate cards
                                 *
                                 * http://stackoverflow.com/questions/27300441/how-do-i-expand-cardviews-to-show-more-detail-like-google-keep-cards
                                 */
                                //Toast.makeText(getActivity(), currentKey, Toast.LENGTH_LONG).show(); // Test Line to Showcase the Key.

                                ActivityOptionsCompat options =
                                        ActivityOptionsCompat.makeSceneTransitionAnimation(getActivity(),
                                                v,   // The view which starts the transition
                                                getString(R.string.transition_taskcard)    // The transitionName of the view we’re transitioning to
                                        );

                                ActivityCompat.startActivity(getActivity(), updateView, options.toBundle());
                            }
                        });
                    }

Just showing this example to let you know that both your view and your deletion code must be dynamic.

If you're doing a dynamic view instead, you an refer to the documentation here https://github.com/firebase/emberfire

UPDATE Since you just added your adapter, it is also possible to have an onClickListener within getView to perform any removal as such if you intend to.

Nicholas
  • 1,883
  • 21
  • 39
  • Okay I see what you did. But how do I get the position of the item to be removed inside `@Override public void onChildRemoved(DataSnapshot dataSnapshot) { }` ? I can get the Key generate by the Firebase database. But that is pretty much it –  Jan 20 '17 at 23:35