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
Related
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.
I have already a Parcelable data class which is used across the module:
#Keep
data class TotalProductValue(val header: String?, val prices: Pricing?, val cta: Cta?) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readParcelable(Pricing::class.java.classLoader),
parcel.readParcelable(Cta::class.java.classLoader),
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(header)
parcel.writeString(subHeader)
parcel.writeParcelable(prices, flags)
parcel.writeParcelable(cta, flags)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<TotalProductValue> {
override fun createFromParcel(parcel: Parcel): TotalProductValue {
return TotalProductValue(parcel)
}
override fun newArray(size: Int): Array<TotalProductValue?> {
return arrayOfNulls(size)
}
}
}
Now I want to add one more parameter as below without impacting other places where it's used, I tried default value and parcel.dataAvail() below but it didn't work. Is there any work around without creating another data class ?
#Keep
data class TotalProductValue(val header: String?, val subHeader: String? = null, val prices: Pricing?, val cta: Cta?) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
if (parcel.dataAvail() > 0) parcel.readString() else null,
parcel.readParcelable(Pricing::class.java.classLoader),
parcel.readParcelable(Cta::class.java.classLoader),
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(header)
parcel.writeString(subHeader)
parcel.writeParcelable(prices, flags)
parcel.writeParcelable(cta, flags)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<TotalProductValue> {
override fun createFromParcel(parcel: Parcel): TotalProductValue {
return TotalProductValue(parcel)
}
override fun newArray(size: Int): Array<TotalProductValue?> {
return arrayOfNulls(size)
}
}
}
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
}
}
}
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.
I would like to be able to receive the individual parameters of my paracable object in the next activity. I believe that I am using the correct method, just do not understand how to output the parameter inputs once in the second activity.
My MainActivty.kt:
package com.example.favouritefood
import android.content.Intent
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.widget.ImageButton
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val food1: ImageButton = findViewById(R.id.imageButtonFood1)
val food2: ImageButton = findViewById(R.id.imageButtonFood2)
val food3: ImageButton = findViewById(R.id.imageButtonFood3)
val food4: ImageButton = findViewById(R.id.imageButtonFood4)
val pizza = Food(
"Pizza", "www.test.com", "Italy, Tomato",
"1/1/2018", "pizza#mail.com", 5)
food1.setOnClickListener()
{
val intent = Intent(this, MetaDataActivity::class.java).apply {
putExtra("Food", pizza)
}
startActivity(intent)
}
}
}
My second activity (to receive the parcelable):
package com.example.favouritefood
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Parcelable
import android.widget.EditText
class MetaDataActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_meta_data)
val name: EditText = findViewById(R.id.editTextName)
val food = intent.getParcelableExtra("Food") as Parcelable
val test = food.writeToParcel(food, 0)
name.setText(test.toString())
}
}
Where food.wrtieToParcel(food, 0) throws a type mismatch of Required: Parcel! Found: Parcelable over food.
How would I go about reading the parameters in the object?
My object class for reference:
package com.example.favouritefood
import android.os.Parcel
import android.os.Parcelable
class Food(val name: String?, val location: String?, val keywords: String?, val date: String?, val email: String?, val rating: Int) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readInt()) {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(name)
parcel.writeString(location)
parcel.writeString(keywords)
parcel.writeString(date)
parcel.writeString(email)
parcel.writeInt(rating)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Food> {
override fun createFromParcel(parcel: Parcel): Food {
return Food(parcel)
}
override fun newArray(size: Int): Array<Food?> {
return arrayOfNulls(size)
}
}
}
You don't need to call val test = food.writeToParcel(food, 0).
use val food = intent.getParcelableExtra("Food") as Food instead.