获取泛型类加载器以解析嵌套的Parcelable泛型字段

问题描述 投票:1回答:3

我有一个Parcelable泛型类型的包装,但Parcel构造无法编译,因为T类不能一般确定

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

    }
}

这种情况有什么解决方案吗?

android generics kotlin parcelable
3个回答
1
投票

您可以使用reified inline function作为工厂方法来实现此目的。我更喜欢在伴侣对象上这样做。这是一个MCVE:

class MyItem<T> (val model: T) {
    companion object {
        inline fun <reified T> from(parcel : T) : MyItem<T> {
            return MyItem<T>(T::class.java.newInstance())
        }
    }
}
fun main(args: Array<String>) {
    val mi = MyItem.from("hi")
    println("mi is a ${mi::class}")
}

1
投票

如果您需要一个Parcel类型的构造函数,您可以将其更改为主构造函数,然后找出MyItem的类型。

class Parcel

class MyItem(val parcel: Parcel) {
    inline fun <reified T> model() : T {
         // You code would be calling
         // `parcel.readParcelable(T::class.java.classLoader)`
        return T::class.java.newInstance() as T
    }
}
fun main(args: Array<String>) {
    // You don't ned to know the out type when constructing MyItem.
    val mi = MyItem(Parcel())

    // But you do need to know it when calling model()
    val model : String = mi.model()

    println("mi.model is a ${model::class}")
}

1
投票

为了得到这里的全貌,我最终得到了:

用例是一个有一个Parcelable泛型实例让我们称它为model,它应该用Parcelable包装器的公共属性来完成,以免污染具有外部字段的模型。例如Item包装。

在下面的示例中,wrapper extra属性为我们提供了某种类型的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)
        }
    }
}

所以最后我们可以得到类似的东西: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
        }
    }
}

扩展类如:

class BasePagerFragment<T : Parcelable> : Fragment(){
    protected fun readBundle(bundle: Bundle?) {
        bundle.getParcelableArrayList<Item<T>>("items")    
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.