how to implement parcelable to ArrayList of Mutable Map? - android

I have this property in my class that the data type is ArrayList<MutableMap<String,Any>> , but I am confused what should I write in parcel constructor and also in writeToParcel method ?
class User() : Parcelable {
var uid : String = ""
var upcomingEvents : ArrayList<MutableMap<String,Any>> = ArrayList()
constructor(parcel: Parcel) : this() {
uid = parcel.readString() ?: ""
upcomingEvents = ....... // <-- what should I write in here ?
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(uid)
parcel........ // <--- and also here ???
}
java or kotlin is okay

As Mohammed Alaa already mentioned, in Kotlin you can use the #Parcelize annotation to have all code generated automatically:
import android.os.Parcel
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
#Parcelize
data class User(var uid: String, var upcomingEvents: List<MutableMap<String, Any>>) :
Parcelable
If you use the Any class, this approach will not work. In that case you could go for changing from Any to a class that is supported by Parcelize or write the code yourself. Something like this:
data class User(var uid: String, var upcomingEvents: List<MutableMap<String, Any>>) :
Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString() ?: "",
readUpcomingEvents(parcel)
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(uid)
parcel.writeList(upcomingEvents)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<User> {
override fun createFromParcel(parcel: Parcel): User {
return User(parcel)
}
override fun newArray(size: Int): Array<User?> {
return arrayOfNulls(size)
}
private fun readUpcomingEvents(parcel: Parcel): List<MutableMap<String, Any>> {
val list = mutableListOf<MutableMap<String, Any>>()
parcel.readList(list as List<*>, MutableMap::class.java.classLoader)
return list
}
}
}

Related

Parcel a List of objects from another Parcelable class in Kotlin

I'm working on a weather app for a class and I'm having some trouble with parcelable. I've looked at several other questions that are similar to this on StackOverflow, but haven't found an answer, so I wanted to throw my specific situation out there.
I have this Data class:
package com.example.weatherapp
import android.os.Parcel
import android.os.Parcelable
data class CurrentConditions(
val weather: List<WeatherCondition>,
val main: Currents?,
val name: String?
) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readParcelableList(List<WeatherCondition>(), WeatherCondition::class.java.classLoader), <-- This line is giving me trouble
parcel.readParcelable(Currents::class.java.classLoader),
parcel.readString()
) {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeParcelable(main, flags)
parcel.writeString(name)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<CurrentConditions> {
override fun createFromParcel(parcel: Parcel): CurrentConditions {
return CurrentConditions(parcel)
}
override fun newArray(size: Int): Array<CurrentConditions?> {
return arrayOfNulls(size)
}
}
}
And on the line I've indicated, I'm trying to parcel a list of WeatherCondition objects, which is another parcelable data class:
package com.example.weatherapp
import android.os.Parcel
import android.os.Parcelable
data class WeatherCondition(
val main: String?,
val icon: String?
) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readString()
) {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(main)
parcel.writeString(icon)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<WeatherCondition> {
override fun createFromParcel(parcel: Parcel): WeatherCondition {
return WeatherCondition(parcel)
}
override fun newArray(size: Int): Array<WeatherCondition?> {
return arrayOfNulls(size)
}
}
}
The empty parentheses at the end of List<WeatherCondition>() have a red line on them. I'm not sure if I need something in the parentheses or if they shouldn't be there at all. If I remove the () then List<WeatherCondition> has the red line instead. Am I even close to on the right track? (This is my first time writing a mobile app, so I'm on a steep learning curve here).
Thanks for any help anyone can offer.

Kotlin Add Parcelable implementation for Array of Double

I'm trying to add the parcelable implementation of a variable declared as an Array of Double.
When I try to generate this implementation automatically with Android Studio, the coordinateskey stays in TODO:
import android.os.Parcel
import android.os.Parcelable
class PointGeoJson (
val type: String = "",
val coordinates: Array<Double> = emptyArray()
) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
TODO("coordinates")
) {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(type)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<PointGeoJson> {
override fun createFromParcel(parcel: Parcel): PointGeoJson {
return PointGeoJson(parcel)
}
override fun newArray(size: Int): Array<PointGeoJson?> {
return arrayOfNulls(size)
}
}
}
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
#Parcelize
class PointGeoJson(
val type: String = "",
val coordinates: Array<Double> = emptyArray()
) : Parcelable
This should work properly

ArrayList<ArrayList<String>> in Parcelable object kotlin

Array of arrays of strings needs to be parcelized. The object is like so
data class Foo (
#SerializedName("bar") val bar: ArrayList<ArrayList<String>>,
)
It doesn't exactly need to be ArrayList. Array can also used.
data class Foo (
#SerializedName("bar") val bar: Array<Array<String>>,
)
Whichever easier is ok to map this json data
{
"bar": [
["a", "b"],
["a1", "b2", "c2"],
["a3", "b34", "c432"]
]
}
Using kotlin experimental Parcelize crashes the app when it's compiled with progaurd
How is it written in "writeToParcel" and read in "constructor"?
data class Foo (
#SerializedName("bar") val bar: ArrayList<ArrayList<String>>,
) : Parcelable {
constructor(source: Parcel) : this(
// ?????
)
override fun writeToParcel(dest: Parcel, flags: Int) = with(dest) {
// ?????
}
}
You can't directly create Parcelable for List of List directly, so one solution is to make one subclass of your desired List as Parcelable and take it as you final list type. How? check out below :
Let's first create our internal List of String class like below :
class StringList() : ArrayList<String>(), Parcelable {
constructor(source: Parcel) : this() {
source.createStringArrayList()
}
override fun describeContents() = 0
override fun writeToParcel(dest: Parcel, flags: Int) {
dest.writeStringList(this#StringList)
}
companion object {
#JvmField
val CREATOR: Parcelable.Creator<StringList> = object : Parcelable.Creator<StringList> {
override fun createFromParcel(source: Parcel): StringList = StringList(source)
override fun newArray(size: Int): Array<StringList?> = arrayOfNulls(size)
}
}
}
What we've done here is created our ArrayList<String> parcelable so that we can use it at any endpoint.
So final data class would be having following implementation :
data class Foo(#SerializedName("bar") val bar: List<StringList>) : Parcelable {
constructor(source: Parcel) : this(
source.createTypedArrayList(StringList.CREATOR)
)
override fun describeContents() = 0
override fun writeToParcel(dest: Parcel, flags: Int) = with(dest) {
writeTypedList(bar)
}
companion object {
#JvmField
val CREATOR: Parcelable.Creator<Foo> = object : Parcelable.Creator<Foo> {
override fun createFromParcel(source: Parcel): Foo = Foo(source)
override fun newArray(size: Int): Array<Foo?> = arrayOfNulls(size)
}
}
}
Note: It's simple implementation based on O.P., you can make any customization based on your requirement.

Parcelable with inheritance in Kotlin- Base class properties not getting parcelized

I have a parent class in Kotlin like this
open class Parent(
var name: String,
var dose: JsonElement?,
val other: String?) {
constructor(name: String, dose: JsonElement?)
: this(
name = name.toLowerCase(),
dose = dose,
other = null
)
}
And its child class like this
class Child(
val type: String,
name: String,
dose: JsonElement?
) : Parent(name, dose), Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString() ?: "",
parcel.readString() ?: "",
Gson().fromJson(parcel.readString(), JsonElement::class.java))
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(type)
parcel.writeString(name)
parcel.writeString(Gson().toJson(dose))
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Child> {
override fun createFromParcel(parcel: Parcel): Child {
return Child(parcel)
}
override fun newArray(size: Int): Array<Child?> {
return arrayOfNulls(size)
}
}
}
My problem here is when I pass object of child class as parcelable only child class properties are propagated. All base class properties like name and dose are null after object is de-serialized.
I have cross-verified order of reading and writing and also verified that values are being written correctly at the time of serialization. Let me know if more information is needed from my side.

Kotlin parcelable and arrayList of parcelables

I am trying to write a parcelable data object to pass to from activityA to activityB in my android application.
My object is passing with all the data, except my arraylist of the class Available Service
data class AvailableService(val id: Int,
val name: String,
val description: String,
val price: Double,
val currency: String,
val imageUrl: String) : Parcelable {
companion object {
#JvmField #Suppress("unused")
val CREATOR = createParcel { AvailableService(it) }
}
protected constructor(parcelIn: Parcel) : this(parcelIn.readInt(),
parcelIn.readString(),
parcelIn.readString(),
parcelIn.readDouble(),
parcelIn.readString(),
parcelIn.readString())
override fun writeToParcel(dest: Parcel?, flags: Int) {
dest?.writeInt(id)
dest?.writeString(name)
dest?.writeString(description)
dest?.writeDouble(price)
dest?.writeString(currency)
dest?.writeString(imageUrl)
}
override fun describeContents() = 0
}
above is the available serviceClass, next I have Trip, which holds an arraylist of AvailableService.. I observed this in debug, it is successfully writing the arraylist, for some reason I have an issue with reading the data.
data class Trip(val id: String,
val status: String,
val orderedServices: ArrayList<OrderedService>) : Parcelable {
companion object {
#JvmField #Suppress("unused")
val CREATOR = createParcel { Trip(it) }
}
protected constructor(parcelIn: Parcel) : this(parcelIn.readString(),
parcelIn.readString(),
arrayListOf<OrderedService>().apply {
parcelIn.readArrayList(OrderedService::class.java.classLoader)
}
)
override fun writeToParcel(dest: Parcel?, flags: Int) {
dest?.writeString(id)
dest?.writeString(status)
dest?.writeList(orderedServices)
}
override fun describeContents() = 0
}
in case someone wonders what's the fun of the CREATOR does, code below:
inline fun <reified T : Parcelable> createParcel(
crossinline createFromParcel: (Parcel) -> T?): Parcelable.Creator<T> =
object : Parcelable.Creator<T> {
override fun createFromParcel(source: Parcel): T? = createFromParcel(source)
override fun newArray(size: Int): Array<out T?> = arrayOfNulls(size)
}
again, writing succeeds, but reading fails, I get an empty arraylist..
I think that part is the faulty one:
arrayListOf<OrderedService>().apply {
parcelIn.readArrayList(OrderedService::class.java.classLoader)
}
is there a different way to read/write arraylist? am I writing it wrong? reading it wrong?
thanks in advance for any help!
Replace:
arrayListOf<OrderedService>().apply {
parcelIn.readArrayList(OrderedService::class.java.classLoader)
}
with:
arrayListOf<OrderedService>().apply {
parcelIn.readList(this, OrderedService::class.java.classLoader)
}
Change
arrayListOf<OrderedService>().apply {
parcelIn.readArrayList(OrderedService::class.java.classLoader)
}
to
source.createTypedArrayList(OrderedService.CREATOR)
Change dest?.writeList(orderedServices)
to dest?.writeTypedList(orderedServices)
The creator method
companion object {
#JvmField
val CREATOR: Parcelable.Creator<Trip> = object : Parcelable.Creator<Trip> {
override fun createFromParcel(source: Parcel): Trip = Trip(source)
override fun newArray(size: Int): Array<Trip?> = arrayOfNulls(size)
}
}
For API 29 and above
Replace:
arrayListOf<OrderedService>().apply {
parcelIn.readArrayList(OrderedService::class.java.classLoader)
}
with
if (Build.VERSION.SDK_INT >= 29)
parcel.readParcelableList(this, OrderedService::class.java.classLoader)
else
parcel.readList(this as List<OrderedService>, OrderedService::class.java.classLoader)
}
and
override fun writeToParcel(dest: Parcel?, flags: Int) {
dest?.writeString(id)
dest?.writeString(status)
dest?.writeList(orderedServices)
}
with
override fun writeToParcel(dest: Parcel?, flags: Int) {
dest?.writeString(id)
dest?.writeString(status)
if (Build.VERSION.SDK_INT >= 29) {
dest?.writeParcelableList(orderedServices,flags)
} else {
dest?.writeList(orderedServices as List<OrderedService>)
}
}
If Parent and Child model have parcelable then used below one
Parent Model
Parcelable {
constructor(parcel: Parcel) : this(
parcel.createTypedArrayList(ImagesModel.CREATOR)
)
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeTypedList(images)
}

Categories

Resources