App crash after sending message to Firebase Database? - android

So I use Firebase Realtime Database for messaging feature and when I send a message, the following error comes out, and the app crash. Later on, the chatting activity keeps crashing, and need to delete the message on Firebase manually to be able to reopen the chatting activity.
2022-07-19 22:56:27.078 21525-21525/com.example.gesit E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.gesit, PID: 21525
com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.String to type com.example.gesit.ChatMessage
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertBean(CustomClassMapper.java:436)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.deserializeToClass(CustomClassMapper.java:232)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertToCustomClass(CustomClassMapper.java:80)
at com.google.firebase.database.DataSnapshot.getValue(DataSnapshot.java:203)
at com.example.gesit.Chatting$listenforMessages$1.onChildAdded(Chatting.kt:86)
at com.google.firebase.database.core.ChildEventRegistration.fireEvent(ChildEventRegistration.java:79)
at com.google.firebase.database.core.view.DataEvent.fire(DataEvent.java:63)
at com.google.firebase.database.core.view.EventRaiser$1.run(EventRaiser.java:55)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135)
Reading message code:
private fun listenforMessages() {
val fromId = FirebaseAuth.getInstance().uid
val toId = toUser?.uid
val ref = FirebaseDatabase.getInstance().getReference("/pesan-pengguna/$fromId/$toId")
ref.addChildEventListener(object : ChildEventListener {
override fun onChildAdded(snapshot: DataSnapshot, previousChildName: String?) {
val chatMessage = snapshot.getValue(ChatMessage::class.java)
if (chatMessage != null) {
Log.d(TAG, chatMessage?.text!!)
if (chatMessage.fromId == FirebaseAuth.getInstance().uid) {
val currentUser = MainScreen.currentUser
adapter.add(ChatItemRight(chatMessage.text, currentUser ?: return))
} else {
adapter.add(ChatItemLeft(chatMessage.text, toUser!!))
}
}
}
override fun onCancelled(error: DatabaseError) {
}
override fun onChildChanged(snapshot: DataSnapshot, previousChildName: String?) {
}
override fun onChildRemoved(snapshot: DataSnapshot) {
}
override fun onChildMoved(snapshot: DataSnapshot, previousChildName: String?) {
}
})
}
JSON DB for messages:
{
"pesan-pengguna": {
"P6scAzLXLcOsDiChjMAXOgnBnar1": {
"nrX4w334X4R4kOyXHfp6rSFPWYv1": {
"fromId": "nrX4w334X4R4kOyXHfp6rSFPWYv1",
"id": "-N7Lf8PyUg9jWKmAv6zr",
"text": "Test 1 2 3",
"timestamp": 1658237785,
"toId": "P6scAzLXLcOsDiChjMAXOgnBnar1"
}
},
"nrX4w334X4R4kOyXHfp6rSFPWYv1": {
"P6scAzLXLcOsDiChjMAXOgnBnar1": {
"fromId": "nrX4w334X4R4kOyXHfp6rSFPWYv1",
"id": "-N7Lf8PyUg9jWKmAv6zr",
"text": "Test 1 2 3",
"timestamp": 1658237785,
"toId": "P6scAzLXLcOsDiChjMAXOgnBnar1"
},
"nrX4w334X4R4kOyXHfp6rSFPWYv1": {
"fromId": "nrX4w334X4R4kOyXHfp6rSFPWYv1",
"id": "-N7LfGGFTKerqT3Lma8Y",
"text": "Test 1 2 3",
"timestamp": 1658237818,
"toId": "nrX4w334X4R4kOyXHfp6rSFPWYv1"
}
}
}
}
Code for ChatMessage:
class ChatMessage(val id: String, val text: String, val fromId: String, val toId: String, val timestamp: Long) {
constructor() : this("","","","", -1)
}

When you're using the following reference:
val ref = FirebaseDatabase.getInstance().getReference("/pesan-pengguna/$fromId/$toId")
And when you attach a ChildEventListener on it, it means that you're trying to read all children that exist within that reference. Now, inside the onChildAdded method you're trying to convert each element into an object of type ChatMessage, which is actually not possible since the children under that node are strings, hence that error. If you want to read a ChatMessage object, please use addListenerForSingleValueEvent, as you can see in the following lines of code:
val valueEventListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
val chatMessage = snapshot.getValue(ChatMessage::class.java)
Log.d("TAG", chatMessage.text)
}
override fun onCancelled(error: DatabaseError) {
Log.d("TAG", error.getMessage()) //Never ignore potential errors!
}
}
ref.addListenerForSingleValueEvent(valueEventListener)
The result in the logcat will be:
Test 1 2 3
Always remember, that Firebase Realtime Database queries work on a flat list. The objects that you want to read must be in a fixed location under each direct child node. If you keep your actual database schema, you won't be able to read the messages that belong to a particular formId. However, this topic was covered several times before, here on StackOverflow. So you should consider creating a schema where all messages exist under a direct node.

Related

How to make my result from firebase database continuously update at realtime?

I've been building an app that allows the user to retrieve and delete some of his own itens registered on Firebase Database, that is my function that allows that (Thanks, Zeeshan):
override suspend fun getAllOnline(): MutableStateFlow<ResourceState<List<DocModel>>> {
auth = FirebaseAuth.getInstance()
val docList: MutableList<DocModel> = suspendCoroutine { continuation ->
database
.child(auth.currentUser!!.uid)
.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
val docList: MutableList<DocModel> = mutableListOf()
for (docs in snapshot.children) {
val doc = docs.getValue(DocModel::class.java)
docList.add(doc!!)
}
continuation.resume(docList) << Line 34 where the error happens
}
override fun onCancelled(error: DatabaseError) {
continuation.resume(emptyList<DocModel>() as MutableList<DocModel>)
}
})
}
return if (docList.isNotEmpty()) {
MutableStateFlow(ResourceState.Success(docList))
} else {
MutableStateFlow(ResourceState.Empty())
}
}
The problem is that I'm not able to delete a file without the app crashing. The error thrown is:
2023-01-01 19:45:12.816 5637-5637/com.tods.docreminder E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.tods.docreminder, PID: 5637
java.lang.IllegalStateException: Already resumed
at kotlin.coroutines.SafeContinuation.resumeWith(SafeContinuationJvm.kt:44)
at com.tods.docreminder.feature.doc.data.repository.remote.DocFirebaseRepositoryImpl$getAllOnline$docList$1$1.onDataChange(DocFirebaseRepositoryImpl.kt:34)
at com.google.firebase.database.core.ValueEventRegistration.fireEvent(ValueEventRegistration.java:75)
at com.google.firebase.database.core.view.DataEvent.fire(DataEvent.java:63)
at com.google.firebase.database.core.view.EventRaiser$1.run(EventRaiser.java:55)
at android.os.Handler.handleCallback(Handler.java:942)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7844)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
As I understood, the problem is that I'm deleting something from web and It's not updating realtime, so it's not able to display the changes on my recycler view (the item is deleted using swipe, so the UI should update it automatically to show the new result to the user).
How would I be able to implement this realtime update from this function?
Any needed code, just tell me and I'll update it asap.
Thanks for your support.
Thanks, Alex!
I used this repository as example: repository.
This is the updated result of the repository:
override suspend fun getAllOnline(): MutableStateFlow<ResourceState<List<DocModel>>> {
auth = FirebaseAuth.getInstance()
val docList = mutableListOf<DocModel>()
val docs = database.child(auth.currentUser!!.uid).get().await()
for(document in docs.children) {
val doc = document.getValue(DocModel::class.java)
docList.add(doc!!)
}
return if (docList.isNotEmpty()) {
MutableStateFlow(ResourceState.Success(docList))
} else {
MutableStateFlow(ResourceState.Empty())
}
}
Now that I'm able to delete, I'll manage the exceptions properly using the Resource State message to send the answer to the user.
Edited:
Now receiving the exception:
override suspend fun getAllOnline(): MutableStateFlow<ResourceState<List<DocModel>>> {
auth = FirebaseAuth.getInstance()
val docState: MutableStateFlow<ResourceState<List<DocModel>>>
val docList = mutableListOf<DocModel>()
docState = try {
val docs = database.child(auth.currentUser!!.uid).get().await()
for(document in docs.children) {
val doc = document.getValue(DocModel::class.java)
docList.add(doc!!)
}
if(docList.isNotEmpty()) {
MutableStateFlow(ResourceState.Success(docList))
} else {
MutableStateFlow(ResourceState.Empty())
}
} catch(e: StorageException) {
MutableStateFlow(ResourceState.Error(e.message))
}
return docState
}
And my ResourceState class if it helps:
sealed class ResourceState<T>(
val data: T? = null,
val message: String? = null
) {
class Success<T>(data: T?): ResourceState<T>(data)
class Error<T>(message: String?, data: T? = null): ResourceState<T>(data, message)
class Loading<T>: ResourceState<T>()
class Empty<T>: ResourceState<T>()
}
Hope it helps =)
the error comes from this line of code:
continuation.resume(docList) << Line 34 where the error
Coroutines are oneShot resume , so if you receive data you resume the first time, second time it will crash, Use Flow or Channel to receive multiple responses

Extract Data from firebase

Unable to extract information from the datasnapshot received from firebase.
Currently, I am able to get the dataSnapshot from firebase, but I am having problems extracting the information from it.
In the example below I have a lobby with the code "81MUB" and inside I have a list of players (only using one player in the example). Data from FireBase
{
"81MUB": [
{
"name": "Alejandro",
"points": 0
}
]
}
Data Class
data class Player(
val name: String,
val points: Int
)
Listener
fun getCode(): String {
val index = ('A'..'Z') + ('1'..'9')
var code = ""
for (i in 0..4){
code += index[Random().nextInt(index.size)]
}
return code
}
class MviewModel : ViewModel() {
private val _Players: MutableLiveData<MutableList<Player>> =
MutableLiveData(mutableListOf<Player>(Player("Alejandro", 0)))
private var _LobbyCode: String = ""
private val dataBase = FirebaseDatabase.getInstance()
fun getPlayer(): MutableLiveData<MutableList<Player>> = _Players
fun createLobby() {
_LobbyCode = getCode()
}
fun listener() {
val postListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
}
override fun onCancelled(databaseError: DatabaseError) {
// Getting Post failed, log a message
}
}
dataBase.reference.child(_LobbyCode).addValueEventListener(postListener)
}
}
Any tips?
Each time you call getCode() you are generating a new random code. When reading data, you always use the exact same code that exists in the database. So in code, it should look like this:
val db = Firebase.database.reference
val codeRef = db.child("81MUB")
codeRef.get().addOnCompleteListener {
if (it.isSuccessful) {
val snapshot = it.result
val name = snapshot.child("name").getValue(String::class.java)
val points = snapshot.child("points").getValue(Long::class.java)
Log.d("TAG", "$name/$points")
} else {
Log.d("TAG", error.getMessage()) //Never ignore potential errors!
}
}
The result in the logcat will be:
Alejandro/0
If you however want to map the 81MUB node into an object of type Player, then your data class should look like this:
data class Player(
val name: String? = null,
val points: Int? = null
)
And in code:
val db = Firebase.database.reference
val codeRef = db.child("81MUB")
codeRef.get().addOnCompleteListener {
if (it.isSuccessful) {
val snapshot = it.result
val player = snapshot.getValue(Player::class.java)
Log.d("TAG", "${player.name}/${player.points}")
} else {
Log.d("TAG", error.getMessage()) //Never ignore potential errors!
}
}
Which will produce the exact same output as above.
You might also take into consideration, using the DatabaseReference#push() method which:
Create a reference to an auto-generated child location. The child key is generated client-side and incorporates an estimate of the server's time for sorting purposes.
Instead of using your codes.

The On Success Listener for query.get() won't execute properly. The code returns an error saying that the load has not been initialized

So, my roommate and I are trying to develop an app to help students living on campus at our school keep track of their laundry. However, we are having trouble creating new laundry loads.
Our addLoad function is supposed to add a LaundryHolder object to Firebase (containing the machine number, whether it is a washer or dryer, who owns the load, and how many seconds are left for the load), whereas the LaundryLoad object contains a LaundryHolder, observer function (notifyDataSetChanged() for the LaundryLoadFragment), and timer (with time form LaundryHolder).
In Firebase, each clothingItem has a load ID with which to identify which load it is in on the user side. For our implementation to work, we need to fetch the ID which Firebase gives our LaundryHolder, which is why we are adding an onSuccessListener to a temporary query. The issue arises, however, when the query doesn't succeed or fail, and we can't figure out what is going on here.
This is the error we get:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: edu.rosehulman.roselaundrytracker, PID: 11847
kotlin.UninitializedPropertyAccessException: lateinit property load has not been initialized
at edu.rosehulman.roselaundrytracker.model.LaundryLoadViewModel.addLoad(LaundryLoadViewModel.kt:42)
at edu.rosehulman.roselaundrytracker.adapter.AddLoadAdapter.addLoad(AddLoadAdapter.kt:67)
at edu.rosehulman.roselaundrytracker.fragment.AddLoadFragment.onCreateView$lambda-1(AddLoadFragment.kt:32)
at edu.rosehulman.roselaundrytracker.fragment.AddLoadFragment.$r8$lambda$lIyFvxsLH_bCt-kHzadMjy2Ls_Y(Unknown Source:0)
at edu.rosehulman.roselaundrytracker.fragment.AddLoadFragment$$ExternalSyntheticLambda0.onClick(Unknown Source:2)
at android.view.View.performClick(View.java:7455)
at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1119)
at android.view.View.performClickInternal(View.java:7432)
at android.view.View.access$3700(View.java:835)
at android.view.View$PerformClick.run(View.java:28810)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7842)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
Does anyone have any idea?
class LaundryLoadViewModel: ViewModel() {
private var loads = ArrayList<LaundryLoad>()
private var curPos = 0
lateinit var ref: CollectionReference
lateinit var uid: String
private var onlyOwned = true
private val subscriptions = HashMap<String, ListenerRegistration>()
fun getPreference() = onlyOwned
fun addLoad(machineNumber: Int, machineType: String, contents: ArrayList<ClothingItem>, time: Long, observer: () -> Unit){
val holder = LaundryHolder(machineNumber, machineType.lowercase(Locale.getDefault()) == "dryer", time * LaundryLoadFragment.SEC_TO_MIN, uid)
// val load = LaundryLoad(holder, observer)
// loads.add(load)
ref.add(holder)
lateinit var load: LaundryLoad
val query = ref
.whereEqualTo("machineNumber",machineNumber)
.whereEqualTo("owner",uid)
query.get().addOnSuccessListener { snapshot ->
snapshot.documents.forEach {
Log.d(Constants.TAG,"Retrieving load from Firebase")
load = LaundryLoad.from(it, observer)
}
}
query.get().addOnFailureListener {
Log.d(Constants.TAG,"Retrieval failed due to $it")
}
// val query = ref.whereEqualTo("machineNumber",machineNumber).whereEqualTo("dryer",machineType.lowercase(Locale.getDefault())=="dryer")
load.addMany(contents)
loads.add(load)
}
fun addListener(fragmentName: String, observer: () -> Unit) {
lateinit var subscription: ListenerRegistration
loads.clear()
val auth = Firebase.auth
val user = auth.currentUser!!
val clothes = ArrayList<ClothingItem>()
uid = user.uid
ref = Firebase.firestore.collection(LaundryLoad.COLLECTION_PATH)
val ref2 = Firebase.firestore.collection(ClothingItem.COLLECTION_PATH)
val inLoadQuery = ref2.whereNotEqualTo("load","")
inLoadQuery.addSnapshotListener { snapshot: QuerySnapshot?, error: FirebaseFirestoreException? ->
error?.let {
Log.d(Constants.TAG, "Error: $it")
return#addSnapshotListener
}
snapshot?.documents?.forEach {
clothes.add(ClothingItem.from(it))
}
}
if(onlyOwned) {
val query = ref.whereEqualTo("owner",uid)
subscription = query
.addSnapshotListener { snapshot: QuerySnapshot?, error: FirebaseFirestoreException? ->
error?.let {
Log.d(Constants.TAG, "Error: $it")
return#addSnapshotListener
}
retrieveLoads(snapshot, clothes, observer)
}
} else {
subscription = ref
.addSnapshotListener { snapshot: QuerySnapshot?, error: FirebaseFirestoreException? ->
error?.let {
Log.d(Constants.TAG, "Error: $it")
return#addSnapshotListener
}
retrieveLoads(snapshot, clothes, observer)
}
}
subscriptions[fragmentName] = subscription
observer()
}
private fun retrieveLoads(snapshot: QuerySnapshot?, clothes: ArrayList<ClothingItem>, observer: () -> Unit) {
snapshot?.documents?.forEach {
loads.add(LaundryLoad.from(it, observer))
}
for (load in loads) {
for (item in clothes) {
if (item.load == load.getId()) {
load.addToLoad(item)
}
}
}
}
fun removeListener(fragmentName: String) {
for(load in loads) {
ref.document(load.getId()).set(load.laundryHolder)
}
subscriptions[fragmentName]?.remove()
subscriptions.remove(fragmentName)
}
fun togglePreference() {
onlyOwned = !onlyOwned
}
}
It looks like ref has not been initialized when you ref.add(holder) in addLoad. It's impossible for us to say why that is, as the code that calls addLoad seems to be missing, but the stack trace should point you pretty directly to where the problem is.

Realtime DB persistence distorts data display in order

When I open an app I display a list of groups which have name, creationDate and etc. One of the fields is recentMessage, which value is ID which points to messages collection's message. I get that recent message by:
fun loadRecentMessage(param: (Message) -> Unit) {
reference.child("/messages/$groupd/messages/$messageid")
.addValueEventListener(object: ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.value != null) {
// If I had a list of ["1", "2", "3", "4", "5"]
// 'messageid' will show to message "5"
// and param will be invoked with it.
(snapshot.getValue(Message::class.java)?.let { param.invoke(it) })
}
}
override fun onCancelled(error: DatabaseError) {
// Log error
}
})
}
Now when I press on group, I navigate to messages fragment and attach childEventListener to messages and display them:
fun loadMsgs(data: MutableLiveData<MutableList<Message>>) {
reference
.child("/messages/$groupid/messages/${messageid}")
.addChildEventListener(object : ChildEventListener {
override fun onChildAdded(snapshot: DataSnapshot, previousChildName: String?) {
// If I have a list of messages: ["1", "2", "3", "4", "5"]
// and I called loadRecentMessage() before, my snapshot values comes in this order:
// "5", "1", "2", "3", "4", "5"
// If I don't call that method or that method uses get(), my messages
// order comes in good order
snapshot.getValue(Message::class.java)?.let { data.addAsynchronous(it) }
}
override fun onChildChanged(snapshot: DataSnapshot, previousChildName: String?) {
// Empty
}
override fun onChildRemoved(snapshot: DataSnapshot) {
// Empty
}
override fun onChildMoved(snapshot: DataSnapshot, previousChildName: String?) {
// Empty
}
override fun onCancelled(error: DatabaseError) {
// Log error
}
}
)
}
The problem is, that my recent message, that I have loaded before, shows up first in the list, even though, it's last. When I use get() instead of addValueEventListener() to load recent message everything is fine, but I need to keep that up to date. I think it's because the persistence had my recent message saved, thus it loads it first. How to display my messages in order, even though I have one message loaded before?
UPDATE 1:
// This is where param.invoke(it) comes in work:
database.getRecentMessage(groupid) {
groupsMutableValue.addAsynchronous(it)
}
// addAsynchronous() method
fun <T> MutableLiveData<MutableList<T>>.addAsynchronous(item: T) {
val newList = mutableListOf<T>()
this.value?.let { newList.addAll(it) }
newList.add(item)
this.postValue(newList)
}
// message list from DB
"messages" : {
"-MXSkzXdm2OxV6CC3Xl3" : {
"messages" : {
"-MXVeBEq5ksZfPn4BoDB" : {
"content" : "Hi",
"from" : "2YnfQSeBladXsD9sPEcKrhxJ6CB2"
},
"-MXVeJ5MBOOzl53kEEC1" : {
"content" : "Hey",
"from" : "2g87tAMuQSOgu7b1W0uOvKDpg3K2"
},
"-MXVeR6vPi7KZ8tC52EP" : {
"content" : "Hola",
"from" : "iLOmzFZqzVRtMb5eOC1gRRWY5Ar2"
},
"-MXXlQVAhbT6JBJbpIRt" : {
"content" : "Last message",
"from" : "2YnfQSeBladXsD9sPEcKrhxJ6CB2"
}
}
}

How to retrieve a child from Firebase when there is a unique key Kotlin

I want to retrieve specific child values like (phonenumber, firstname, familyname) from Firebase real time database
but there is a unique key for each user
and this is the tree:
I've tried this:
var loginRef = rootRef.child("users").orderByChild("phoneNumber").equalTo(phone).addListenerForSingleValueEvent(
object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
// Get data object and use the values to update the UI
val phoneNumber = dataSnapshot.getValue<User>()!!.phoneNumber
// ...
Toast.makeText(applicationContext, "phone number is: $phoneNumber", Toast.LENGTH_LONG).show()
}
override fun onCancelled(databaseError: DatabaseError) {
// Getting Data failed, log a message
Log.w(TAG, "LoginData:onCancelled", databaseError.toException())
// ...
Toast.makeText(applicationContext, "error", Toast.LENGTH_LONG).show()
}
})
and I have a simple model called User to handle the data (I know the passwords should be hashed here)
#IgnoreExtraProperties
data class User(
var firstName: String? = "",
var fatherName: String? = "",
var familyName: String? = "",
var phoneNumber: String? = "",
var password: String? = ""
) {
#Exclude
fun toMap(): Map<String, Any?> {
return mapOf(
"firstName" to firstName,
"fatherName" to fatherName,
"familyName" to familyName,
"phoneNumber" to phoneNumber,
"password" to password
)
}
}
but dataSnapshot.getValue<User>()!!.phoneNumber will never work, since the first node retrieved in this query is the unique key
what I need is something like dataSnapshot.child("unique-key/phoneNumber").value for each child i want to use, but a way easier and more efficient than making .addChildEventListener for each node
Let's firstly give some notes one the code:
first thing you need to be aware of is here:
dataSnapshot.getValue<User>()!!.phoneNumber
as it might be null if phoneNumber doesn't exist and will throw an error.
secondly, assuming you made some null handling it will still retrieve you empty string, because what you sent to model is just the unique key, and of course you can't handle it with this model.
The easiest way to solve this and get the children of retrieved node is by using for loop according to this solution: https://stackoverflow.com/a/38652274/10324295
you need to make for loop puts each item into an array list, try this code:
val userList: MutableList<User?> = ArrayList()
var loginRef = rootRef.child("users").orderByChild("phoneNumber").equalTo(phone).addListenerForSingleValueEvent(
object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
userList.clear()
for (userSnapshot in dataSnapshot.children) {
val user: User? = userSnapshot.getValue(User::class.java)
userList.add(user)
// Get Data object and use the values to update the UI
// ...
Toast.makeText(applicationContext, "hi: ${user!!.phoneNumber}", Toast.LENGTH_LONG).show()
}
}
override fun onCancelled(databaseError: DatabaseError) {
// Getting Data failed, log a message
Log.w(TAG, "LoginData:onCancelled", databaseError.toException())
// ...
Toast.makeText(applicationContext, "error", Toast.LENGTH_LONG).show()
}
})
var loginRef = rootRef.child("users").orderByChild("phoneNumber").equalTo(phone).addListenerForSingleValueEvent(
object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
// retreive all children firstly by foreach
dataSnapshot.children.forEach { data ->
val userModel = data.getValue(User::class.java)
val phoneNumber = userModel!!.phoneNumber
Toast.makeText(applicationContext, "phone number is: $phoneNumber",
Toast.LENGTH_LONG).show()
}
// ...
}
override fun onCancelled(databaseError: DatabaseError) {
// Getting Data failed, log a message
Log.w(TAG, "LoginData:onCancelled", databaseError.toException())
// ...
Toast.makeText(applicationContext, "error",
Toast.LENGTH_LONG).show()
}
})

Categories

Resources