How to get specific values from all UserID (UID) and save in RecyclerViewFirebaseUI - android

How can I get the UID from all users from my database with the structure below and save it in my FirebaseRecyclerviewUI? I have tried for several hours but my recycler view still displays null.
-User
|
-uid
|
-advert
|
-bus_name
-category
-purl
-id
Below is my getter/setter BusinessListData class that serves as the model for receiving the values and sending them to recyclerview
class BusinessListData {
var id: String = ""
var propixurl: String = ""
var business_name: String = ""
var category: String = ""
constructor(){
}
constructor(id: String, propixurl: String, business_name: String, category: String) {
this.id = id
this.propixurl = propixurl
this.business_name = business_name
this.category = category
}
fun getID(): String{
return id
}
fun getUrl(): String{
return propixurl
}
fun getBusName(): String{
return business_name
}
fun getCate(): String{
return category
}
fun setID(id: String){
this.id = id
}
fun setUrl(propixurl: String){
this.propixurl = propixurl
}
fun setBusName(business_name: String){
this.business_name = business_name
}
fun setCate(category: String){
this.category = category
}
}
My FirebaseRecyclerViewUI details are below. The mDatabase is the reference to the database and I tried getting the snapshot of the data which was successful according to my Log.v values. The problem is that I could not get the specific values under the Advert tree in my Firebase RealTime Database
mDatabase = FirebaseDatabase.getInstance().reference
val options: FirebaseRecyclerOptions<BusinessListData> = FirebaseRecyclerOptions.Builder<BusinessListData>()
.setQuery(mDatabase, object: SnapshotParser<BusinessListData> {
override fun parseSnapshot(snapshot: DataSnapshot): BusinessListData {
Log.v("snapshotfire", snapshot.toString()) //returns all snapshot values
Log.v("snapshotfire", snapshot.child("purl").toString()) // this returns null
Log.v("snapshotfire", snapshot.child("bus_name").getValue().toString()) //this also returns null
return BusinessListData(snapshot.child("id").getValue().toString(),
snapshot.child("purl").getValue().toString(),
snapshot.child("bus_name").getValue().toString(),
snapshot.child("category").getValue().toString()
)
}
})
.build()

When you set a certain query or database reference to the FirebaseUI adapters, it will show each child node of that reference/query. Since you pass in the root of your database, your parseSnapshot will be called for each child node of the root, which does not seem to be what you want.
To show the child nodes of the User node, pass in a reference to that node:
mDatabase = FirebaseDatabase.getInstance().reference
val options: FirebaseRecyclerOptions<BusinessListData> = FirebaseRecyclerOptions.Builder<BusinessListData>()
.setQuery(mDatabase.child("User"), object: SnapshotParser<BusinessListData> {
...
Now your parseSnapshot will be called for each child node of User, and you can get the necessary keys/values from that snapshot.
For example, to get the UID you can either read the snapshot's key or its advert/uid property:
override fun parseSnapshot(snapshot: DataSnapshot): BusinessListData {
Log.v("snapshotfire", snapshot.key)
Log.v("snapshotfire", snapshot.child("advert/id").getValue())
)

Related

Values are not added in an array instead it keeps updating value at 0th index in Firebase Firestore

On clicking like button , it is not either increasing like count in UI nor adding a userid in likes array. It is not adding a userid into an array instead it is updating value at 0th index. I am attaching photos of logic to add values in array in firestore.
I have also added the project on github. Please take a look at it for more clearification.
https://github.com/Anshi10/Social-Media-App
Post data class which has array of user ids which liked a post.
data class Post(
val text : String = "" ,
val createdBy : user = user() ,
val createdAt : Long = 0L ,
val Likes : ArrayList<String> = ArrayList()
)
Post Dao for adding post into firestore and updating likes
class PostDao {
val db = FirebaseFirestore.getInstance()
val PostCollection = db.collection("Post")
val auth = Firebase.auth
fun addPost(text : String){
//!! is to ensure that post is created only when user is logged in otherwise it will count as illegal exception
val currentUserId = auth.currentUser!!.uid
val userdao = userDao()
GlobalScope.launch{
//getuserbyid return task which will turn into object of user data class
val Postuser = userdao.getuserbyId(currentUserId).await().toObject(user::class.java)!!
//this will give the time when the post is created
val currentTime = System.currentTimeMillis()
val post = Post(text,Postuser,currentTime)
PostCollection.document().set(post)
}
}
fun getPostById(postid : String) : Task<DocumentSnapshot>{
return PostCollection.document(postid).get()
}
fun updateLikes(postid: String) {
GlobalScope.launch {
val currentUserid = auth.currentUser!!.uid
val post = getPostById(postid).await().toObject(Post::class.java)!!
val isliked = post.Likes.contains(currentUserid)
if (isliked) {
post.Likes.remove(currentUserid)
} else {
post.Likes.add(currentUserid)
}
PostCollection.document(postid).set(post)
}
Log.d("msg","updateLikes called")
}
}
onBindViewHolder function
override fun onBindViewHolder(holder: PostViewHolder, position: Int, model: Post) {
holder.userName.text = model.createdBy.name
holder.userText.text = model.text
//with(context) load(url) into(view)
Glide.with(holder.userImage.context).load(model.createdBy.imageUrl).circleCrop().into(holder.userImage)
holder.Likecount.text = model.Likes.size.toString()
holder.userTime.text = Utils.getTimeAgo(model.createdAt)
val auth = FirebaseAuth.getInstance()
val currentuserId = auth.currentUser!!.uid
val isliked = model.Likes.contains(currentuserId)
if(isliked){
holder.likeButton.setImageDrawable(ContextCompat.getDrawable(holder.likeButton.context,R.drawable.ic_baseline_favorite_24))
}
else{
holder.likeButton.setImageDrawable(ContextCompat.getDrawable(holder.likeButton.context,R.drawable.unliked))
}
}
}
Firestore structure
first collection named post which contains field createdAt , createdBy,likesCount,text of the post.
second collection named users which contains field id , imageUrl , name

Expected a List while deserializing, but got a class java.util.HashMap with nested object

I have problem with nesting data class. Here is my data classes:
#Entity(tableName = "categories_table")
data class Category(
var details: String = "",
#PrimaryKey
var id: String = "",
var lastUpdated: Long = -1,
var name: String = "",
var order: Int = -1,
val specialities: ArrayList<String> = arrayListOf()
)
And here is my DB:
I using this code for get data from database:
val valueEventListener = object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
categories.clear()
specialities.clear()
for (cat in snapshot.children){
val category: Category? = cat.getValue(Category::class.java)
for (spec in cat.children){
spec.getValue(String::class.java)?.let { specialities.add(it) }
}
category?.let { categories.add(it) }
}
_categories.value = categories
}
override fun onCancelled(error: DatabaseError) {
throw error.toException()
}
}
categoryRef.addListenerForSingleValueEvent(valueEventListener)
I have red many themes with this problem but can't find solution and always get this error:
Expected a List while deserializing, but got a class java.util.HashMap
Edit
I have a progress)
for (cat in snapshot.children) {
val categoryMap: Map<String, Any> = cat.value as Map<String, Any>
val category = Category(details = categoryMap.getValue("details").toString(), name = categoryMap.getValue("name").toString(),
id = categoryMap.getValue("id").toString(), lastUpdated = categoryMap.getValue("lastUpdated").toString().toLong(),
order = categoryMap.getValue("order").toString().toInt())
categories.add(category)
I'm not sure that i'm parsing map correct, but it's work. Tell me please if i wrong)
The problem seems to come from val specialities: ArrayList<String> = arrayListOf().
In order for the specialties in your database screenshot to be seen as a List, they'd have a defined order with sequential, numeric keys: 0, 1, 2, etc. What you have however is a bunch of keys, each with a value or a nested object, which is translates to Map<String, Object>.
val specialities: Map<String, Object> = mapOf()

how to get position of deleted Firestore Data that have been deleted from console (outside source) to update Or notify the adapter

I have this app that someone can delete his document at any time so if he deletes the document I want every other user to get updated the document has been removed and remove the document from the listView, it's more like a Food Ordering app so the user order could be taking by another Driver so the document will no longer be available for other users, I want to update the recyclerView Whenever a user deletes a document, so how to get the position without clicking how to detect that change to get the position, Sorry if I couldn't explain much I'm Using Groupie Adapter
val ref = firestore.collection("orders").whereNotEqualTo("userUid", uid)
val adapter = GroupAdapter<GroupieViewHolder>()
ref.addSnapshotListener { value, error ->
if (error != null){
return#addSnapshotListener
}
value?.documentChanges?.forEach {
if (it.type == DocumentChange.Type.ADDED) {
val userUid = it.document.data.get("userUid") as String
val userPhone = it.document.data.get("phone") as String
val userName = it.document.data.get("name") as String
val time = it.document.data.get("time") as String
val marketName = it.document.data.get("marketName") as String
val amount = it.document.data.get("amount") as String
val storeimgUrl = it.document.data.get("storeImg") as String
val order = it.document.data.get("order") as String
val userImg = it.document.data.get("userImg") as String
adapter.add(DriverOrders(userUid, userPhone, userName, time, marketName, amount, storeimgUrl, order, userImg))
adapter.notifyDataSetChanged()
}
if(it.type == DocumentChange.Type.REMOVED){
// here Wher I'm trying to get the position of deleted Or removed data
if (it.document.id == DriverOrders.docId){
adapter.notifyItemRemoved(it.oldIndex)
}
}
}
recyclerview_driverorders.adapter = adapter
}
class DriverOrders(val userUid: String, val userPhone: String,
val userName: String, val time: String,
val marketName: String, val amount: String, val storeimgUrl: String, val order: String,
val userImg: String):Item<GroupieViewHolder>() {
override fun getLayout(): Int {
return R.layout.driver_row
}
override fun bind(viewHolder: GroupieViewHolder, position: Int) {
viewHolder.itemView.driverorders_sName.text = marketName
viewHolder.itemView.driverorders_order.text = order
viewHolder.itemView.driverorders_time.text = Date
Picasso.get().load(storeimgUrl).fit().into(viewHolder.itemView.driverorders_sImg)
}
}

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.

How to separate some text of string from list?

I tried to take a string from list but I want to separated that string become 2.
This is my list [Aquaman (1), Bumblebee (3), Spiderman into the spider verse (4), Bohemian Rhapsody (7), A Star Is Born (8), Mary Poppins Returns (9), Captain Marvel (10), Ralph Breaks the Internet (11), Avengers: Endgame (12)]
I want to separate the title and the number on it become 2 string but there are still one because I want to use the title for view and I want to use the number for id that I want to post. Can I do that? Please help.
This is my model
class Movie2 (
#SerializedName("id")
var movieId: String? = null,
#SerializedName("description")
var synopsis: String? = null,
#SerializedName("release_date")
var release: String? = null,
#SerializedName("poster")
var poster: String? = null,
#SerializedName("genre")
var genre: String? = null,
#SerializedName("title")
var title: String? = null
)
{
override fun toString(): String {
return "$title ($movieId)"
}
}
this is where i have to put the data
override fun showMovieList(data: List<Movie2>) {
movies = data[0]
reviews.clear()
reviews.addAll(data)
data.forEach {
title = it.title!!
id = it.movieId!!
}
Log.v("id", "" + id)
Log.v("title", "" + title)
searchSpn.adapter = ArrayAdapter<Movie2>(this, R.layout.spinner_item, reviews)
movie = searchSpn.selectedItem.toString()
}
val lData = listOf<String>()
lData.forEach {
val data = it.split("(")
val id = data[1].split(")")[0]
val title = data[0]
}
its better you create class model like "Movie" with proprety uid and title
or you can keep in hashMap() like this
val lData = listOf<String>()
val lisofMovie = mutableListOf<HashMap<String, String>>()
lData.forEach {
val data = it.split("(")
val id = data[1].split(")")[0]
val title = data[0]
val lMovie = HashMap<String, String>()
lMovie["id"] = id
lMovie["title"] = title
lisofMovie.add(lMovie)
}
Its not quite clear what your issue is but you seem to want to use just the title in the spinner, then one way to do this would be to override toString as you have done, but it sounds like you just want the title, so I think it should be.
override fun toString(): String {
return title?:"no title provided"
}
This does not change your underling list, or the objects in the list, so when you select an item you can get it via onItemSelected method, for example from the documentation.
class SpinnerActivity : Activity(), AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>, view: View, pos: Int, id: Long) {
// An item was selected. You can retrieve the selected item using
// parent.getItemAtPosition(pos)
}
override fun onNothingSelected(parent: AdapterView<*>) {
// Another interface callback
}
}
In your case you should get an instance of your Movie2 class, and then you can get the id my just calling parent.movieId

Categories

Resources