Update value from realtime database after button click - android

I'm trying to create a like functionality in my app, the like function is already working (increment and decrement). My problem is I need to re-enter the activity again to see the new value of the like. But the value in my realtime database is already changed but in the app view, it doesn't increment or decrement (Need to re-enter to see the new value). How do i refresh a value in my app when in a button click? The code is below
//set the likes number on start
likes.text = myPlants.likes.toString();
//When like is clicked
bulbLike.setOnCheckListener(object : OnCheckListener {
override fun onChecked(view: ExpressView?) {
bulbLike(myPlants.plantId,currentUser!!.uid)
//When i remove this the values dosent change
val rootRef = FirebaseDatabase.getInstance().reference
val likeRef = rootRef.child("plants").child(myPlants.plantId).child("likes")
likeRef.get().addOnCompleteListener(OnCompleteListener<DataSnapshot?> { task ->
if (task.isSuccessful) {
val value: Long? = task.result.getValue(Long::class.java)
likes.text = value.toString()
} else {
Log.d("TAG", "Error") //Don't ignore potential errors!
}
})
}
override fun onUnChecked(view: ExpressView?) {
bulbDislike(myPlants.plantId,currentUser!!.uid)
//When i remove this the values dosent change
val rootRef = FirebaseDatabase.getInstance().reference
val likeRef = rootRef.child("plants").child(myPlants.plantId).child("likes")
likeRef.get().addOnCompleteListener(OnCompleteListener<DataSnapshot?> { task ->
if (task.isSuccessful) {
val value: Long? = task.result.getValue(Long::class.java)
likes.text = value.toString()
} else {
Log.d("TAG", "Error") //Don't ignore potential errors!
}
})
}
})
This one works it changes the value but it changes to 1 or -1
This is method or like and dislike
private fun bulbLike(plantId: String, userId: String) {
val dPlant: DatabaseReference = FirebaseDatabase.getInstance().reference
dPlant.child("plants").child(plantId).child("likes").setValue(ServerValue.increment(1))
dPlant.child("plants").child(plantId).child("userLikes").child(userId).child("status").setValue("Liked")
}
private fun bulbDislike(plantId: String, userId: String) {
val dPlant: DatabaseReference = FirebaseDatabase.getInstance().reference
dPlant.child("plants").child(plantId).child("likes").setValue(ServerValue.increment(-1))
dPlant.child("plants").child(plantId).child("userLikes").child(userId).child("status").setValue("Dislike")
}

This here gets the data once, don't use it in your case:
//THIS WONT LISTEN TO UPDATES:
likeRef.get().addOnCompleteListener(OnCompleteListener<DataSnapshot?> { task ->
if (task.isSuccessful) {
val value: Long? = task.result.getValue(Long::class.java)
likes.text = value.toString()
} else {
Log.d("TAG", "Error") //Don't ignore potential errors!
}
})
Read like this instead, using ValueEventListener, like this:
//THIS WILL LISTEN TO UPDATES DIRECTLY
val postListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
//set likes here
val value = dataSnapshot.getValue(Long::class.java)
likes.text = value.toString()
}
override fun onCancelled(databaseError: DatabaseError) {
// Getting Post failed, log a message
Log.w(TAG, "loadPost:onCancelled", databaseError.toException())
}
}
likeRef.addValueEventListener(postListener)

Related

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.

Kotlin Firebase foreach child in path

I have a simple to-do app in Kotlin and I want to get data from "task" node in firebase on app startup. For each child, I want to create a Todo object.
var todo = Todo("child data here")
Getting specific task
val database = FirebaseDatabase.getInstance()
val ref = database.getReference("task")
var todo = ref.child("task1").key?.let { Todo(it) }
if (todo != null) {
todoAdapter.addTodo(todo)
}
I want to get all children, there can be more than three.
If you want to get all children of a particular node, no matter how many are actually present there, then you should loop over that node using getChildren() method, as you can see in the following lines of code:
val db = FirebaseDatabase.getInstance().reference
val taskRef = db.child("task")
val valueEventListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
for (ds in dataSnapshot.children) {
val value = ds.getValue(String::class.java)
Log.d("TAG", value)
//Create the desired object
var todo = Todo(value) //👈
}
}
override fun onCancelled(error: DatabaseError) {
Log.d("TAG", error.getMessage()) //Never ignore potential errors!
}
}
taskRef.addListenerForSingleValueEvent(valueEventListener)
The result in the logcat will be:
task1
task2
task3
.....

How to get elements from a condition node in a Realtime Database Firebase

I need to get from the Firebase Realtime Database node, not the entire list, but only the one that contains the value "ok".
I can get the whole list using the User model
val list:List<User> = it.children.map {it.getValue(User::class.java)}
If you need to get only the users that have the id property set to "ok", then you should use a Query line in the following lines of code:
val rootRef = FirebaseDatabase.getInstance().reference
val usersRef = rootRef.child("users")
val okQuery = usersRef.orderByChild("id").equalTo("ok")
val valueEventListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
for (ds in dataSnapshot.children) {
val user = ds.getValue(User::class.java)
Log.d("TAG", ds.key + " -> " + user.id)
}
}
override fun onCancelled(databaseError: DatabaseError) {
Log.d("TAG", databaseError.getMessage()) //Don't ignore errors!
}
}
okQuery.addListenerForSingleValueEvent(valueEventListener)
The result in the logcat will be:
kolya -> ok
sasha -> ok

How to propery listen to child changes in FirebaseDatabase

I am trying to listen to my database child changes, in my case it is orders.
Below is a picture of my database, where
ODdPag... Is the uid of my customer
Lu-_1A is just .push random order naming
I can provide my code but it is confusing and not working, because i can only access Orders and not its next child.
Now I want to list all my orders and lister for changes in sub children (in order names) not uid.
I am using:
val db = FirebaseDatabase.getInstance.reference
val ref = db.child("/Orders/")
ref.addChildEventListener(object: ChildEventListener {
override fun onChildAdded(p0: DataSnapshot, p1: String?) {
ringtone.play()
itemListTable.clear()
p0.children.forEach {
it.child("order").children.forEach{ item ->
val newData = item.getValue(itemListData::class.java) ?: return
newData.itemName = item.key!!
newData.orderKey = it.key!!
itemListTable.add(newData)
}
val data = it.getValue(itemRowData::class.java) ?: return
adapter.add(itemRow(data.phoneNumber,data.time,data.locationLat,data.locationLong,data.optionalAddress,data.optionalNote,data.totalPrice,itemListTable,it.key))
}
}
override fun onChildChanged(p0: DataSnapshot, p1: String?) {
Log.d("ac1234","$p0")
p0.child("order").children.forEach{ item ->
Log.d("ac1234","1")
val newData = item.getValue(itemListData::class.java) ?: return
Log.d("ac1234","2")
newData.itemName = item.key!!
newData.orderKey = p0.key!!
itemListTable.add(newData)}
val data = p0.getValue(itemRowData::class.java) ?: return
adapter.add(itemRow(data.phoneNumber,data.time,data.locationLat,data.locationLong,data.optionalAddress,data.optionalNote,data.totalPrice,itemListTable,p0.key))
}
class itemRowData(val phoneNumber :String = "",val time :String = "",val locationLat :Double = 0.0,val locationLong :Double = 0.0,val optionalAddress :String = "",val optionalNote :String = "",val totalPrice :String = "")
class itemListData(var itemName: String = "" ,val totalQuantity: String = "",val totalPrice :Long = 0,var orderKey :String = "")
Logcat: 1 and 2 are not called
P0 shows 4 rows full of all data every time I send an order
I want all orders from all users, that is my problem. I cant reference to every ("/Orders/uid") to listen to child changes
To get all orders of all users, you should use a ValueEventListener, like in the following lines of code:
val rootRef = FirebaseDatabase.getInstance().reference
val ordersRef = rootRef.child("Orders")
val valueEventListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
for (uidDataSnapshot in dataSnapshot.children) {
for (orderDataSnapshot in uidDataSnapshot.children) {
val newData = orderDataSnapshot.getValue(itemListData::class.java)
itemListTable.add(newData)
}
}
}
override fun onCancelled(databaseError: DatabaseError) {
Log.d(TAG, databaseError.getMessage()) //Don't ignore errors!
}
}
ordersRef.addValueEventListener(valueEventListener)
See, in order to get each order of each user, you should iterate twice, once to get the uidDataSnapshot and then to get the orderDataSnapshot object.

Decide to create a new item or update an old one in firebase

I have two methods, in one I create a new list item, in the second I update the current list item.
private fun addTarget() {
val name = nameEditText?.text.toString().trim()
val description = descriptionEditText?.text.toString().trim()
if (!TextUtils.isEmpty(name)) {
val id: String = databaseReference?.push()?.key.toString()
val target = Target(guid = id, name = name, description = description)
databaseReference?.child(id)?.setValue(target)
} else Log.d("some", "Enter a name")
}
private fun updateTarget() {
val name = nameEditText?.text.toString().trim()
val description = descriptionEditText?.text.toString().trim()
val map = mapOf("name" to name, "description" to description)
databaseReference?.child(arguments?.getString(KEY_TARGET_GUID, "") ?: "")?.updateChildren(map)
}
I need to clearly separate these two concepts, so there is a problem in the condition.
button?.setOnClickListener { if (condition?????) addTarget() else updateTarget() }
For example, in the Realm there is a method copyToRealmOrUpdate which looks for the field and if it finds it updates it if not then creates a new note. How can I do something like this in firebase?
I resolved my problem next:
When I go to the fragment I pass the guid from the list of all elements and if it is empty then I add if not then update.
button?.setOnClickListener {
if (arguments?.getString(KEY_TARGET_GUID, "").isNullOrEmpty()) addTarget()
else updateTarget()
}
I don't know how this is a good solution.
This is possible in Firebase if you are using exist() method like in the following lines of code:
val valueEventListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
if (dataSnapshot.exists()) {
//Do the update
} else {
//Do the addition
}
}
override fun onCancelled(databaseError: DatabaseError) {
Log.d(TAG, databaseError.getMessage()) //Don't ignore errors!
}
}
databaseReference.child("-LaVYDBpwiIcwhe9qz2H").addListenerForSingleValueEvent(valueEventListener)

Categories

Resources