Search code examples
androidgenericskotlinparcelable

Get generics class loader for parsing nested Parcelable generic field


I have a wrapper of Parcelable generic type but Parcel constructing fails to compile because T class can not be determined generically

class MyItem<T : Parcelable> (val model: T) : Parcelable {
    constructor(parcel: Parcel) : 
      this(parcel.readParcelable(T::class.java.classLoader)) {

    }
}

Is there any solution to this case?


Solution

  • In order to get the whole picture here is what I ended up with:

    The use case is one has a Parcelable generic instance let's call it model which should be completed with common properties of Parcelable wrapper in order to not pollute the model with extrinsic fields. For example Item wrapper.

    In the example below the wrapper extra property gives us some type of index :

    class Item<T : Parcelable> (val model: T, val index: Int ) : Parcelable {
    
        constructor(parcel: Parcel) :
            this(parcel.readParcelable(
              Item<T>::model.javaClass.classLoader),
              parcel.readInt()
            ) {}
    
        override fun writeToParcel(parcel: Parcel?, flag: Int) {
            parcel?.writeParcelable(model, 0)
            parcel?.writeInt(index)
        }
    
        override fun describeContents(): Int {
            return 0
        }
    
        companion object CREATOR : Parcelable.Creator<Item<Parcelable>> {
            override fun createFromParcel(parcel: Parcel): Item<Parcelable> {
                return Item(parcel)
            }
    
            override fun newArray(size: Int): Array<Item<Parcelable>?> {
                return arrayOfNulls(size)
            }
        }
    }
    

    So in the end we can have something like: Item(Person("John"), 0), Item(Person("Bill"), 1)...

    class PersonPagerFragment() : BasePagerFragment<Person>() {
        companion object {
            fun newInstance(itemList: ArrayList<Item<Person>>) 
              : PersonPagerFragment {
    
                val args = Bundle()
                val fragment = PersonPagerFragment()
                args.putParcelableArrayList("items", itemList)
                fragment.arguments = args
    
                return fragment
            }
        }
    }
    

    extending class like:

    class BasePagerFragment<T : Parcelable> : Fragment(){
        protected fun readBundle(bundle: Bundle?) {
            bundle.getParcelableArrayList<Item<T>>("items")    
        }
    }