Mathieu
Mathieu

Reputation: 1703

Issues to pass objects as parameters from activity to fragment

I am trying to pass an object as a parameter from an activity to a fragment.

I already searched over hill and dale to find out how to do it, I tried many methods but none of them worked.

Here is what I tried :

// In my Activity, where I call my fragment
var bundle = Bundle()
bundle.putParcelable("restaurant", restaurant)
var fragment = Home2Fragment()
fragment.arguments = bundle
supportFragmentManager.beginTransaction().replace(R.id.content, fragment, FRAGMENT_HOME).commit()

My IDE (Android Studio) underline "restaurant" in bundle.putParcelable line, telling me a type mismatch. This is the same with the getArguments() methods, I get a type mismatch.

My class look like this :

@Parcel
class Establishment {

    var title = ""
    // More variables

    fun loadFromJson(json: JsonObject) {
        title = readString(json, TAG_TITLE)
        // More API loads
    }

    companion object {
        private const val TAG_TITLE = "title"
        // More tags
    }
}

I don't understand why my class is set as "Parcel" but is not recognized as a "Parcelable".

I am looking for an efficient way to pass parameters from an activity to a fragment.

Thanks a lot in advance.


EDIT :

As asked, I tried to make it as Serializable. I can't make it Serializable, as "Serializable" does not exists.

But I tried to make it "SerializedName", but "This annotation is not applicable to target 'class' "

Upvotes: 1

Views: 357

Answers (2)

Mathieu
Mathieu

Reputation: 1703

So with your help I finally found out how to do this.

In my fragment, I modified my newInstance() fun :

companion object {
    fun newInstance(restaurant : Establishment) : Home2Fragment {
        val fragment = Home2Fragment()
        val args = Bundle()

        args.putParcelable("restaurant", restaurant)
        fragment.arguments = args

        return (fragment)
    }
}

This was not very difficult, it was before as my IDE was telling me that my object "Establishment" was not a Parcelable Object.

So the real problem was to set "Establishment" as a Parcelable Object.

It gave me hard time so I decided to use Parcelable Generator plugin, as adviced by TpoM6oH.

My class Establishment now look like this :

@Parcel
class Establishment() : Parcelable {

    var title = ""
    // More var

    fun CREATOR(): Parcelable.Creator<Establishment> = object : Parcelable.Creator<Establishment> {
        override fun createFromParcel(p0: android.os.Parcel?): Establishment {
            return Establishment()
        }

        override fun newArray(p0: Int): Array<Establishment> {
            return null as Array<Establishment>
        }
    }

    constructor(parcel: android.os.Parcel) : this() {
        this = parcel.readString()
        // More var
    }

    fun loadFromJson(json: JsonObject) {
        title = readString(json, TAG_TITLE)
        // More load from API
    }

    companion object {
        private const val TAG_TITLE = "title"
    }

    override fun writeToParcel(parcel: android.os.Parcel, flags: Int) {
        parcel.writeString(title)
        // More var
    }

    override fun describeContents() : Int {
        return 0
    }
}

The plugin Parcelable Generator added some mysterious functions in my class, and "Establishment" (line 2) is still a problem in my IDE opinion ("This class implements Parcelable but does not provide a CREATOR field").

But the code DOES compile ! And it is working !

Thanks everyone for your advice.

Upvotes: 0

reixa
reixa

Reputation: 7011

Your class should implement Parcelable this way:

class Establishment(val title: String) : Parcelable {

    private constructor(p: Parcel) : this(
        title = p.readString(),

    override fun writeToParcel(dest: Parcel, flags: Int) {
        dest.writeString(title)
    }

    override fun describeContents() = 0

    companion object {
        @JvmField val CREATOR = object : Parcelable.Creator<Establishment> {
            override fun createFromParcel(parcel: Parcel) = Establishment(parcel)
            override fun newArray(size: Int) = arrayOfNulls<Establishment>(size)
        }
    }

    fun loadFromJson(json: JsonObject) {
        title = readString(json, TAG_TITLE)
        // More API loads
    }
}

Upvotes: 3

Related Questions