Search code examples
androidfirebasekotlinfirebase-realtime-databasepersistence

Can't access a Firebase node to retrieve a channel list for app


I have code that should update the list and then notifyDataSetChanged() to the list adapter once all of the nodes related to the channel in my Firebase Database is deleted, except after deleting the channel node under /channellist does not get deleted, and my subsequent child listener for /channellist is not able to access data under the ref.child("/channellist/$channelname"). So for some reason I can't access /channellist.

enter image description here

You can see that there is no channel2 under the /channel node, because that was deleted and for some reason the channel2 under channellist was not.

Here is my code for the delete and list update functions:

fun deleteChannel() {
    Log.d("channeltodelete", channelToDelete)
    val messageKeysToDelete = ArrayList<String>()
    fb.child("/channel/$channelToDelete/messages")
        .addListenerForSingleValueEvent(object : ValueEventListener {
            override fun onDataChange(data: DataSnapshot) {
                if (!data.exists()) {
                    deleteChannelHelper(channelToDelete)
                    fb.child("/channel/$channelToDelete").removeValue()
                    return
                }
                // Deletes the messages under /message
                val messagemap = data.getValue(typeindicator2)!!
                for (key in messagemap) {
                    messageKeysToDelete.add(key.key)
                }

                for (key in messageKeysToDelete) {
                    fb.child("message/$key").removeValue()
                }

                // DeleteChannelHelper deletes under user/channels
                deleteChannelHelper(channelToDelete)
                var fb2 = FirebaseDatabase.getInstance().reference

                fb.child("/channel/$channelToDelete").removeValue()

                **// This is the line of code that doesn't work
                fb2.child("/channellist/$channelToDelete").removeValue()**
            }

            override fun onCancelled(databaseError: DatabaseError) {
                // report/log the error
            }
        }

fun processChannelListData(data: DataSnapshot) {
    Log.d("channellistlistener", data.key + ": " + data.value)
    val channelnames = data.children.toMutableList()
    var channels = ArrayList<String>()
    var channelsToDelete = ArrayList<String>()
    for (channel in channelnames) {
        channels.add(channel.key.toString())
    }
    Log.d("channelnameslistener", channels.toString())

    // If a channel was added
    for (channel in channels) {
        if (channel !in channelList) {
            channelList.add(channel)
        }
    }

    // If a channel was deleted
    for (channel in channelList) {
        if (channel !in channels) {
            channelsToDelete.add(channel)
        }
    }

    channelList.removeAll(channelsToDelete)
    Log.d("chanList removeall", channelList.toString())

    myAdapter.notifyDataSetChanged()
}

What I'm noticing is that the the ChildEventListener, which is placed at /channellist, fires multiple times not only at the /channellist node, but once for all the child nodes as well for some reason and it messes up the global channelList because if the last node accessed was test1, it looks like

2020-09-14 16:26:18.734 24448-24523/com.example.treechat D/channellistlistener: test1: -MGyjrKRLmc-wPLAjvR-
2020-09-14 16:26:18.734 24448-24523/com.example.treechat D/channelnameslistener: []
...
2020-09-14 16:26:18.734 24448-24523/com.example.treechat D/chanList removeall: []

whereas the code if it was just the top level node would be fine

2020-09-14 16:26:18.733 24448-24520/com.example.treechat D/channellistlistener: channellist: {channel1=-MHCK1wp8mBUi_bJzxZ-, channel2=-MHDAM_k2no7ZLtUYTIU, test1=-MGyjrKRLmc-wPLAjvR-}
2020-09-14 16:26:18.733 24448-24520/com.example.treechat D/channelnameslistener: [channel1, channel2, test1]
...
2020-09-14 16:26:18.733 24448-24520/com.example.treechat D/chanList removeall: [channel1, channel2, test1]

By the way I don't have problems accessing /channellist when creating the channel, as you can see the node was created fine. But for some reason the app crashes when I do that, and instead of going from ChannelListActivity -> ChannelActivity, it goes from ChannelListActivity -> ChannelActivity -> mini-crash -> ChannelListActivity. I'll post that in a separate question, but there are no fatal exception logs.


Solution

  • I reverted to using a ValueEventListener for /channellist instead of a ChildEventListener.

    I found out that using a HashMap<String, Any?>() and putting the path with null as the value for all the locations I wanted to delete worked to delete all the nodes at once, including in channellist. Once you have the HashMap, you need to call updateChildren(HashMap) on the database reference.