Getting data from firebase in androd studio - android

How to get data from firebase?
I can implement some data on it, but I do now know why I cannot get and put it in my activity, application.
This is my ValuEventListener, should I use here Livedata?
class FirebaseDB : LiveData<List<Shopping>>() {
var fbItemCount:Long = 0
private val firebaseDB2: FirebaseDatabase = FirebaseDatabase.getInstance()
private val userID = FirebaseAuth.getInstance().uid
public val ref = firebaseDB2.getReference("user/"+userID.toString())
fun removeAll() {
}
fun delete(shopping: Shopping){
}
fun modify(shopping: Shopping) {
}
fun add(shopping: Shopping) {
ref.child(shopping.id.toString()).setValue(shopping)
}
fun getShopping(): List<Shopping> {
val lista: ArrayList<Shopping> = ArrayList()
ref.addValueEventListener(object : ValueEventListener{
override fun onDataChange(dataSnapshot: DataSnapshot) {
for (messageSnapshot in dataSnapshot.children) {
val shopping: Shopping = Shopping(id = messageSnapshot.child("id").value as Long,
product = messageSnapshot.child("product").value as String,
quantity = messageSnapshot.child("quantity").value as String,
price = messageSnapshot.child("price").value as String,
bought = messageSnapshot.child("bought").value as Boolean)
//Log.i("readDB", "$product $quantity $price $isbought")
lista.add(shopping)
}
}
override fun onCancelled(error: DatabaseError) {
Log.e("MyAdapter", "Failed to delete value.",error.toException())
}
})
fbItemCount = lista.size.toLong()
return lista
}
}
How can i check if it is downloaded somewhere on my app or I just cannot see it or implement well.
EDIT:
I just added log.v... and it starts working...
However after adding a new element in the list, new element is added with double information from firebase for example:
In database I have:
Orange
Apples
I add:
Bananas
Now in application it is like:
Orange
Apples
Orange
Apples
Bananas

onDataChange is an async callback and does not result in the same thread, so return one liveData and observe it, then in the on data change process the list and post it on the liveData.
fun getShopping(): LiveData<List<Shopping>> {
val lista: ArrayList<Shopping> = ArrayList()
val data=MutableLiveData<List<Shopping>>()
ref.addValueEventListener(object : ValueEventListener{
override fun onDataChange(dataSnapshot: DataSnapshot) {
for (messageSnapshot in dataSnapshot.children) {
val shopping: Shopping = Shopping(id = messageSnapshot.child("id").value as Long,
product = messageSnapshot.child("product").value as String,
quantity = messageSnapshot.child("quantity").value as String,
price = messageSnapshot.child("price").value as String,
bought = messageSnapshot.child("bought").value as Boolean)
//Log.i("readDB", "$product $quantity $price $isbought")
lista.add(shopping)
}
fbItemCount = lista.size.toLong()
data.postValue(lista)
}
override fun onCancelled(error: DatabaseError) {
Log.e("MyAdapter", "Failed to delete value.",error.toException())
}
})
return data
}

About your double items problem this code making it because before making ValueEventListener you created an empty list then after get data from firebase in onDataChange method you add all items that firebase returns then suppose you add a new item by calling 'add' method them onDataChange will be triggered again and giving you again all items with a new one added, but you never remove the old item and add these new items again to this list. That's why it's happening
val lista: ArrayList<Shopping> = ArrayList()
ref.addValueEventListener(object : ValueEventListener{
override fun onDataChange(dataSnapshot: DataSnapshot) {
for (messageSnapshot in dataSnapshot.children) {
val shopping: Shopping = Shopping(id = messageSnapshot.child("id").value as Long,
product = messageSnapshot.child("product").value as String,
quantity = messageSnapshot.child("quantity").value as String,
price = messageSnapshot.child("price").value as String,
bought = messageSnapshot.child("bought").value as Boolean)
//Log.i("readDB", "$product $quantity $price $isbought")
lista.add(shopping)
}
}
override fun onCancelled(error: DatabaseError) {
Log.e("MyAdapter", "Failed to delete value.",error.toException())
}
})
Correct code would be like this:
var lista = emptyList<Shopping>()
ref.addValueEventListener(object : ValueEventListener{
override fun onDataChange(dataSnapshot: DataSnapshot) {
lista = emptyList()
for (messageSnapshot in dataSnapshot.children) {
val shopping: Shopping = Shopping(id = messageSnapshot.child("id").value as Long,
product = messageSnapshot.child("product").value as String,
quantity = messageSnapshot.child("quantity").value as String,
price = messageSnapshot.child("price").value as String,
bought = messageSnapshot.child("bought").value as Boolean)
//Log.i("readDB", "$product $quantity $price $isbought")
lista.add(shopping)
}
}
override fun onCancelled(error: DatabaseError) {
Log.e("MyAdapter", "Failed to delete value.",error.toException())
}
})

Related

How can I populate my RecyclerView from multiple nodes of my Firebase Realtime Database?

I am looking for a way to populate my RecyclerView. I know how to populate a RecyclerView from a single node of my database but I wonder how can I get data from multiple nodes. In my app the user can select multiple hobbies. And I want to populate a recycler view depending which hobbies the user has selected.
Here is a picture of my user node from my database
As you can see my user has selected the hobbies Caffe's,Camping,Hiking
I have a node called Locations and there a six child nodes Caffe's,Camping,Hiking,Museums,Night life and restaurants. Here is my Locations node
I get users hobbies from this code block
val currentuid = FirebaseAuth.getInstance().currentUser!!.uid
val getCurrentUserHobbies =
FirebaseDatabase.getInstance().getReference("users/$currentuid/hobbies")
getCurrentUserHobbies.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
val value = snapshot.getValue(String::class.java)
val valueAsString = value.toString()
if (valueAsString.contains("Hiking")){
}
}
override fun onCancelled(error: DatabaseError) {
}
})
If I want to get my recycler view to show all Hiking locations I do this:
val adapter = GroupAdapter<GroupieViewHolder>()
val hikingRef = FirebaseDatabase.getInstance().getReference("Locations/Hiking")
hikingRef.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
for (snap in snapshot.children) {
val recommendItems = snap.getValue(RecommendationsClass::class.java)
if (recommendItems != null) {
adapter.add(RecommendationsAdapter(recommendItems))
}
}
recommendationsRecyclerView.adapter = adapter
}
override fun onCancelled(error: DatabaseError) {
}
})
Now if the user has selected hiking and camping for example. I want my recycler view to show all locations from nodes Locations/Hiking and Locations/Camping. I tried multiple but nothing works. I am not going to write them here because it will take too much space. I am trying to keep my question as simple as possible.
Thanks in advance!
I unfortunately could not find any possible solution how to make it work. I had to do something different. What I did I copied sub nodes from my Locations node and put them in users/currentuid/Recommendations depending which hobbies my current user has.
Here is the code snipped that does that:
val currentuid = FirebaseAuth.getInstance().currentUser!!.uid
val getCurrentUserHobbies = FirebaseDatabase.getInstance().getReference("users/$currentuid/hobbies")
getCurrentUserHobbies.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
val value = snapshot.getValue(String::class.java)
val valueAsString = value.toString()
if (valueAsString.contains("Caffe's")) {
val ref = FirebaseDatabase.getInstance().getReference("Locations/Caffe's/")
ref.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
for (snap in dataSnapshot.children) {
val data = dataSnapshot.value
val newData = mapOf("Recommendations/${dataSnapshot.key}" to data)
FirebaseDatabase.getInstance().getReference("users")
.child(currentuid).updateChildren(newData)
}
}
override fun onCancelled(databaseError: DatabaseError) {
// Handle error
}
})
}
if (valueAsString.contains("Camping")) {
val ref = FirebaseDatabase.getInstance().getReference("Locations/Camping/")
ref.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
for (snap in dataSnapshot.children) {
val data = dataSnapshot.value
val newData = mapOf("Recommendations/${dataSnapshot.key}" to data)
FirebaseDatabase.getInstance().getReference("users")
.child(currentuid).updateChildren(newData)
}
}
override fun onCancelled(databaseError: DatabaseError) {
// Handle error
}
})
}
if (valueAsString.contains("Hiking")) {
val ref = FirebaseDatabase.getInstance().getReference("Locations/Hiking/")
ref.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
for (snap in dataSnapshot.children) {
val data = dataSnapshot.value
val newData = mapOf("Recommendations/${dataSnapshot.key}" to data)
FirebaseDatabase.getInstance().getReference("users")
.child(currentuid).updateChildren(newData)
}
}
override fun onCancelled(databaseError: DatabaseError) {
// Handle error
}
})
}
}
override fun onCancelled(error: DatabaseError) {
}
})
What the code above does it checks if caffe's camping and hiking exists in my users/currentuid/hobbies node. If it does it copies the data from Locations and puts it in users/currentuid/Recommendations.
Note: I also have to check for remaining three hobbies. I only put three of them for testing purposes.
Here is also an image to show what I did
After this I only looped through my Recommendations node and added all the locations to my recycler view with this code snippet:
val recommendedLocations = FirebaseDatabase.getInstance().getReference("users/$currentuid/Recommendations")
recommendedLocations.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
for (parentSnapshot in snapshot.children) {
for (childSnapshot in parentSnapshot.children) {
val recommendItems = childSnapshot.getValue(RecommendationsClass::class.java)
if (recommendItems != null) {
adapter.add(RecommendationsAdapter(recommendItems))
}
}
}
recommendationsRecyclerView.adapter = adapter
}
override fun onCancelled(error: DatabaseError) {
}
})

How to get specific data from Firebase with Kotlin

So I have a movie app. If I liked the movie I'm gonna save its id to firebase. And my goal is to get all movie_id's and display them on screen.
This is the saving code.
firebaseDb.getReference("Users").child(uid).child("movie")
.push().child("movie_id")
.setValue(args.movie.id)
And this is the firebase display
So how to get all movie_id's? I tried this but nothing happened.
firebaseDb.getReference("Users").child(uid).child("movie").addValueEventListener(object :
ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
val map: Map<String, Any> = snapshot.getValue() as Map<String, Any>
val mapSize = map.keys.size
for (i in 1..mapSize) {
val keys = map.filterKeys { it == map.keys.toTypedArray()[i - 1] }
}
}
If want to create a list of movie IDs, then use the following lines of code:
val uid = FirebaseAuth.getInstance().currentUser?.uid
val db = FirebaseDatabase.getInstance().reference
val movieRef = db.child("Users").child(uid).child("movie")
val valueEventListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
val movieIds = mutableListOf<String>()
for (ds in dataSnapshot.children) {
val movieId = ds.child("movie_id").getValue(String::class.java)
movieIds.add(movieId)
}
Log.d("TAG", movieIds.size.toString())
}
override fun onCancelled(error: DatabaseError) {
Log.d("TAG", error.getMessage()) //Never ignore potential errors!
}
}
movieRef.addListenerForSingleValueEvent(valueEventListener)
The result in the logcat will be:
2
As I only see two movies in the screenshot.

Firebase Querying many child based on one attribute value from one of them

My Firebase storge
from the image above, I want to get all the milk powder based on the barcode of one of them
var query: Query = FirebaseDatabase.getInstance().getReference("Barcode")
.orderByChild("itemBarcode")
.equalTo(read)
where 'read' is the barcode number I only get one item,
I want instead to get all the item type and wight based on barcode number
like:
SELECT itemWieght, itemName, itemPrice FROM barcode WHERE itemBarcode.itemType = itemType or something like this
EDIT :
here is my part of the code if that's helps
var query: Query = FirebaseDatabase.getInstance().getReference("Barcode")
.orderByChild("itemBarcode")
.equalTo(read)
//Adapter
query.addValueEventListener(object : ValueEventListener {
override fun onCancelled(p0: DatabaseError) {
}
override fun onDataChange(p0: DataSnapshot) {
myBarcodeArray?.clear()
for (r in p0.children) {
var infoHolder = r.getValue(BarcodeInfo::class.java)
myBarcodeArray!!.add(infoHolder!!)
}
val infoAdapter = BarcodeResultAdapter(applicationContext, myBarcodeArray!!)
view.listOfBarcodeResult.adapter = infoAdapter
}
})
EDIT 2:
I tried also to use 2 queries, but it shows empty results
myDataRef?.child("Barcode")?.orderByChild("itemBarcode")?.equalTo(read)?.addListenerForSingleValueEvent(object : ValueEventListener{
override fun onCancelled(p0: DatabaseError) {
}
override fun onDataChange(p0: DataSnapshot) {
var result = p0.getValue(BarcodeInfo::class.java)
myDataRef?.child("Barcode")?.orderByChild(result?.itemWeight.toString())?.equalTo(read)?.addValueEventListener(object : ValueEventListener{
override fun onCancelled(p0: DatabaseError) {
}
override fun onDataChange(p0: DataSnapshot) {
for (r in p0.children){
var holder = r.getValue(BarcodeInfo::class.java)
myBarcodeArray!!.add(holder!!)
}
val infoAdapter = BarcodeResultAdapter(applicationContext, myBarcodeArray!!)
view.listOfBarcodeResult.adapter = infoAdapter
}
})
}
})
If you want get all value inside an item (data snapshot) that mean you should catch a whole of that item so add your query to ListenerForSingleValueEvent
Reference : Query firebase data in Android
I did it by using "Kiet Phan" advice and used 2 query statement like this :
var query: Query = FirebaseDatabase.getInstance().getReference("Barcode")
.orderByChild("itemBarcode")
.equalTo(read)
query.addValueEventListener(object : ValueEventListener {
override fun onCancelled(p0: DatabaseError) {}
override fun onDataChange(p0: DataSnapshot) {
myBarcodeArray?.clear()
for (r in p0.children) {
var infoHolder = r.getValue(BarcodeInfo::class.java)
type = infoHolder?.itemType.toString()
}
var query2: Query = FirebaseDatabase.getInstance().getReference("Barcode")
.orderByChild("itemType")
.equalTo(type)
query2.addValueEventListener(object : ValueEventListener{
override fun onCancelled(p0: DatabaseError) {}
override fun onDataChange(p0: DataSnapshot) {
for (r in p0.children) {
var infoHolder = r.getValue(BarcodeInfo::class.java)
type = infoHolder?.itemType.toString()
myBarcodeArray!!.add(infoHolder!!)
}
val infoAdapter = BarcodeResultAdapter(applicationContext, myBarcodeArray!!)
view.listOfBarcodeResult.adapter = infoAdapter
}
})
}
})
thanks to everyone for help

On Groupie Recycler view every 7 rows it repeats the same uid of firebase database

I dont know what to do in this case because every 7 rows the image drawable is favorite even when it shouldn't be.
class RecipesActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_recipes)
getRecipes()
}
companion object{
val REC_KEY = "REC_KEY"
}
var adapter = GroupAdapter<GroupieViewHolder>()
private fun getRecipes(){
val ref = FirebaseDatabase.getInstance().getReference("/recipes")
val adapter = GroupAdapter<GroupieViewHolder>()
ref.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(p0: DataSnapshot) {
p0.children.forEach{
val reci = it.getValue(Recipes::class.java)
if(reci != null) {
adapter.add(RecipesItem(reci))
}
}
adapter.setOnItemClickListener{ item, view ->
val recItem = item as RecipesItem
val intent = Intent(view.context, RecipeDetail::class.java)
intent.putExtra(REC_KEY, recItem.recipes)
startActivity(intent)
}
recycler_recipes.adapter = adapter
}
override fun onCancelled(p0: DatabaseError) {
}
})
}
}
This class is to put the items in the views. I need them to be, but when I check for favourite or not there's the problem.
class RecipesItem(val recipes: Recipes): Item<GroupieViewHolder>(){
override fun bind(viewHolder: GroupieViewHolder, position: Int) {
viewHolder.itemView.name_recycler.text = recipes.reci_name
viewHolder.itemView.type_recipes.text = recipes.reci_diet
viewHolder.itemView.timeToPrepare.text = recipes.reci_time.plus(" min")
//checkiffav
val user = FirebaseAuth.getInstance().currentUser!!.uid
val fav = FirebaseDatabase.getInstance().getReference("/users/$user/fav_recipes/${recipes.id}")
fav.addListenerForSingleValueEvent(object: ValueEventListener{
override fun onDataChange(p0: DataSnapshot){
if(p0.exists()){
viewHolder.itemView.favorite.setImageResource(R.drawable.favorite)
}
}
override fun onCancelled(p0: DatabaseError) {
}
})
}
override fun getLayout(): Int {
return R.layout.row_recipes
}
}
Basically I have 20 recipes and I have a favorite system, but the recycler view only gets the id of the recipes on every 7 rows, then it repeats the same id's! I'm really new to kotlin and firebase and I dont know how to solve. On every 7 rows the recipe appears has fav because the id that the firebase reference is getting is the same as the first one.
Answered on Groupie issue tracker: https://github.com/lisawray/groupie/issues/320#issuecomment-581915693

Display target data from firebase

I display a list of my targets in fragmentA, when I click on one of them, I pass the guid of this target to the fragmentB
After that, I try in the fragmentB display the data of this target for this guid:
private fun fetchTarget(guid: String) {
val uid = firebaseUser!!.uid
// Attach a listener to read the data at the target id
databaseReference?.child("targets")?.child("users")
?.child(uid)?.child("targets")?.child(guid)?.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
val data = dataSnapshot.value as? HashMap<String, String>?
val name = data?.get("name") ?: ""
val description = data?.get("description") ?: ""
if (name.isEmpty()) Log.d("some", "nameIsEmpty")
else updateViewsContent(name = name, description = description)
}
override fun onCancelled(databaseError: DatabaseError) {
Log.d("some", databaseError.message)
}
})
}
Here I get the guid: -LmfEVnwgqCUqt7beHDg
And in my console i have next structure:
Unfortunately I can't display data of target, though like all the chains I installed
Q: How i can download -LmfEVnx-y7c3oh8_U9F ?
To display the data that belongs to a single guid, you should use a query and then iterate through the DataSnapshot object like in the following lines of code:
val uid = FirebaseAuth.getInstance().currentUser!!.uid
val rootRef = FirebaseDatabase.getInstance().reference
val targetsRef = rootRef!!.child("targets").child("users").child(uid).child("targets")
val query = targetsRef.orderByChild("guid").equalTo("-LmfEVnwgqCUqt7beHDg")
val valueEventListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
for (ds in dataSnapshot.children) {
val target = ds.getValue(Target::class.java)
Log.d(TAG, target.name)
}
}
override fun onCancelled(databaseError: DatabaseError) {
Log.d(TAG, databaseError.getMessage()) //Don't ignore errors!
}
}
query.addListenerForSingleValueEvent(valueEventListener)
The result in the logcat will be:
fgg
You are not getting any data because to get above data your guid value in query should be "-LmfEVnx-y7c3oh8_U9F" but you are passing "-LmfEVnwgqCUqt7beHDg".
You can try below query to get above data:
val uid = firebaseUser!!.uid
// Attach a listener to read the data at the target id
databaseReference?.child("targets")?.child("users")?.child(uid)?.child("targets")?.orderByChild("guid").equalTo(guid)?.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
val data = dataSnapshot.value as? HashMap<String, String>?
val name = data?.get("name") ?: ""
val description = data?.get("description") ?: ""
if (name.isEmpty()) Log.d("some", "nameIsEmpty")
else updateViewsContent(name = name, description = description)
}
override fun onCancelled(databaseError: DatabaseError) {
Log.d("some", databaseError.message)
}
})

Categories

Resources