How to get value from firebase realtime database in android? - android

This is the picture of my firebase database I am trying to store "brand" as an arrayList.
Below is my code
var brandArrayList= ArrayList<BrandModel>()
database= FirebaseDatabase.getInstance()
mRef=database.getReference("brand")
mRef.addValueEventListener(object :ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
for (childSnapshot in snapshot.children) {
val getBrand= childSnapshot.getValue<BrandModel>(BrandModel::class.java)
getBrand!!.item_id=childSnapshot.key
brandArrayList.add(getBrand!!)
}
}
}
override fun onCancelled(error: DatabaseError) {
Log.i("Error",error.toString())
}
})
I am getting error at the line
val getBrand= childSnapshot.getValue(BrandModel::class.java)
I have defined my Model classes as given below
#Parcelize
data class BrandModel(var item_id:String?=null,
var name:String?=null,
var sizeinfo:List<SizeModel>?=null):Parcelable
#Parcelize
data class SizeModel(var quantity:String?=null,
var name:String?=null):Parcelable
I am getting this error
com.google.firebase.database.DatabaseException: Expected a List while
deserializing, but got a class java.util.HashMap

A List in Kotlin code translates to the following structure in the database:
"sizeinfo": {
"0": { ... },
"1": { ... },
"2": { ... },
}
Only when you have sequential numbers in the keys will Firebase convert it to a List. When the keys are of a different format, such as in your case, it gets converted into a Map.
So you'll either need to change the data structure, or (more likely) change the code to match the JSON: Map<String, SizeModel>.

Related

Can't convert String to data class objects - Firebase realtime database [duplicate]

This question already has an answer here:
com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.String to type Data class object KOTLIN
(1 answer)
Closed 1 year ago.
I have read other comments on this same issue, but none of them has touched on a situation like mine
In mine, below describes how the data is structured:
{
"symbols":{
"alphabets":{
"a":{
"available":true,
"text":"A",
"timestamp":1.512686825309134E9
},
"b":{
"available":true,
"text":"B",
"timestamp":1.512687248764272E9
}"NameOfSymbols":"alphabets"
}
}
}
*The reason why mine is showing the error is that it can't convert the string "NameOfSymbols" : "alphabets" to the objects as specified in the data class
So, what can be done about it, I use Kotlin
Is there a way I can exclude that part of the children value while I only get the one that is specified in the data class?
Data Class
data class alphabets(
val name: Names,
var NameOfSymbols: String? = null) {
data class Names(
var available: Boolean? = null,
var text: String? = null,
var timestamp: Long? = null) {
}
}
This structure might work for your case (untested):
data class Message(
#PropertyName("symbols") val symbols: Symbols,
)
data class Symbols(
#PropertyName("alphabets") val alphabets: Alphabets,
)
data class Alphabets(
#PropertyName("a") val a: Alphabet,
#PropertyName("b") val b: Alphabet,
#PropertyName("NameOfSymbols") val nameOfSymbols: String,
)
data class Alphabet(
#PropertyName("available") val available: Boolean,
#PropertyName("text") val text: String,
#PropertyName("timestamp") val timestamp: Long,
)
Usage would be:
// in your ValueEventListener
override fun onDataChange(snapshot: DataSnapshot) {
val value = snapshot.getValue<Message>()
}
If you want to exclude your NameOfSymbols, you should remove it, and add the #IgnoreExtraProperties, like shown below:
#IgnoreExtraProperties
data class Alphabets(
#PropertyName("a") val a: Alphabet,
#PropertyName("b") val b: Alphabet,
)
NOTE, I used these versions of firebase database:
implementation 'com.google.firebase:firebase-database:19.7.0'
implementation 'com.google.firebase:firebase-database-ktx:19.7.0'
ok, After reading the documentation on Structuring Database on the firebase docs website, Structure your database
I realised that i didn't structure my database well, i should have regrouped them after specifying the name
like below
{
// This is a poorly nested data architecture, because iterating the children
// of the "chats" node to get a list of conversation titles requires
// potentially downloading hundreds of megabytes of messages
"chats": {
"one": {
"title": "Historical Tech Pioneers",
"messages": {
"m1": { "sender": "ghopper", "message": "Relay malfunction found. Cause: moth." },
"m2": { ... },
// a very long list of messages
}
},
"two": { ... }
}
}
Although, it said that structuring it that way isn't a nice way, it seems that's what works for me

how do i retrieve data from firebase realtime database using kotlin

Im trying to pull data from firebase realtime database but i'm not sure how to pull more than one data piece at the same time if its possible.
so this is what the database looks like:
so far i have managed to be able to print out all of these values in the following way:
private fun getData() {
var currentUid = mAuth.currentUser?.uid
val myRef = database.getReference("User-following").child(currentUid!!)
myRef.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
val children = dataSnapshot.value
Log.e("Database", "value = $children")
}
override fun onCancelled(error: DatabaseError) {
Log.e("Database", error.toString())
}
})
}
when it prints the value of children i get all 5 in the following format:
E/Database: value = {-MLwcu81dicGo1NezqJD=1, -MLwcwBjdjRo-vgSkEjR=1, -MLwep1w5z4DfGeabx0d=1, -MLw_sc6aHPxPpGBIpCL=1, -MLwdqVch3iDr3GXylln=1}
how to i return each individual id so that i can use it to retrieve the data that corresponds to each id?
To access the individual child nodes under the snapshot you retrieved, you'll want to loop over its children.
override fun onDataChange(dataSnapshot: DataSnapshot) {
for (childSnapshot in dataSnapshot.children) {
Log.i("Database", "child key = $childSnapshot.key")
}
}
Also see the Firebase documentation on listening to value events.

How can I get data from firebase to data model?

I'm quite new at Kotlin. I have data class which hold image urls named testModel. I need to add data to model from firebase with that code:
Here my data model: class testModel(val imageLinks: List<String>)
private val dbRef = FirebaseDatabase.getInstance().reference.child("categories").child("1").child("top")
fun readDataFromFirebase(){
dbRef.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
var list = ArrayList<testModel>()
for (e in dataSnapshot.children){
println(e.value)
}
}
override fun onCancelled(databaseError: DatabaseError) {
Log.e("DB", "loadPost:onCancelled", databaseError.toException())
}
})
}
Actually this block can get value from firebase I can see in run console my image urls but I can't add these on my testModel. How can I make it? Also I need good tutorials for these kind of works, like data models, read and write data with Kotlin. I am waiting for your advice.
PS: I already tried getValue method but is give error java.lang.
In your dataclass, change List<String> with ArrayList<String>, because the type List<E> does not exist in firebase, but arrays do.
Save your data as an Array<String> in firebase and then when you retrieve your snapshot, do snapshot.toObject(TestModel::class)

how to check if firebase have value1 and value2 exist

I'm trying to do the following in my Android application using Kotlin :
I have the Firebase data structure as shown in this image:
The user is able to choose 2 stations from the stations included in the data, either as "start_station", "end_station" or "station_number".. in the next function am trying to take the user's selections and check if both are encluded in the same line.
private fun fetchingLinesData(
theEndStation: String,
theStartStation: String,
) {
val database = FirebaseDatabase.getInstance()
val myRef = database.getReference("line")
myRef.addValueEventListener(object : ValueEventListener {
override fun onCancelled(p0: DatabaseError) {
toast(getString(R.string.could_not_find_a_way))
}
override fun onDataChange(p0: DataSnapshot) {
p0.children.forEach{
//Here should be the line that checks if both data exist
}
}
})
}
Tried using This hasChild Method but it wasn't right.
Try to convert your response to HashMap and search using containsValue
override fun onDataChange(p0: DataSnapshot) {
p0.children.forEach {
//Here should be the line that checks if both data exist
if(it.hasChildren()) {
val stationLines = it.value as HashMap<String, Any>
val validStart = stationLines.containsValue(theStartStation)
val validEnd = stationLines.containsValue(theEndStation)
...
}
}
}
You can do a query:
myRef.orderByChild("end_station").equalTo(theEndStation).addValueEventListener
This will retrieve the data according to the query, then inside onDataChange() after the forEach you can do the following:
if(p0.exists()){
// retrieve data here
}
Using exists() you can check if the datasnapshot exists.
This query will only check for end_station, if you want to check both, then after the query inside the if statement you can retrieve the first_station:
if(p0.exists()){
val firstStation = it.child("start_station").value
And check if firstStation is equal to theStartStation

Parsing boolean from Firebase Database Snapshot

I'm having issues pasing a Snapshot from the Firebase Realtime Database into a Data Class in Kotlin using ProGuard.
Here's how the data looks in the Firebase console:
Here's how I've modeled that data class In my android app:
data class PickupCode(
val code: String,
val boxId: String,
val orderId: String,
val suborderId: String,
val drawers: List<Int>,
val isDelivered: Boolean
) {
constructor(): this("", "", "","", emptyList(), false)
override fun toString(): String {
return code
}
}
Here's how I build the database request:
val reference = database.getReference("pickupCodes/$boxId/$code")
val listener = object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists()) {
println(snapshot)
val pickupCode = snapshot.getValue<PickupCode>(PickupCode::class.java)
pickupCode?.let {
println("Code: ${it.code}, is delivered: ${it.isDelivered} to drawers: ${it.drawers.toString()}")
if (!it.isDelivered) {
// No success
} else {
// Success!
}
} ?: run {
// No success
}
} else {
// No success
}
}
override fun onCancelled(error: DatabaseError) {
// No success
}
}
This is what the println(snapshot) line prints:
DataSnapshot { key = 320625, value = {isDelivered=true, code=320625, drawers={0=2}, orderId=-LhdzXS4-gyT0ysNe-zi, suborderId=-LhdzYhT78y9b3iJcyrb, boxId=box_1} }
And this is what the next print 3 lines lates prints:
Code: 320625, is delivered: false to drawers: [2]
Here I would expect is delivered to be true, but for some reason true-value of isDelivered from the snapshot, is ignored when parsing the snapshot into a PickupCode-class. The value isDelivered of the PickupCode, is equal to the empty constructor of the class.
But WHY and HOW to fix?
All the other values from the snapshot gets parsed corrently. I'm new to Android, but I have a hunch that ProGuard (whatever that is) has some of the blame here.. Here's how I've set it up:
-keepattributes Signature
-keepclassmembers class PickupCode.** {
*;
}
I found a solution to this..
When inspecting the verbose logs I found this:
W/ClassMapper: No setter/field for isDelivered found on class com.x.y.models.PickupCode
After playing a bit around, I found that for some weird reason, the setters for properties starting with is are ignored :S I tested with other property names as well and types.. fx. val isBerp: Number gets the same warning.
So after changing the property name from isDelivered to delivered in both the class and firebase, it works..
I wasn't able to find documentation for this behaviour, so if someone knows about it, it would appreciate a link..

Categories

Resources