获取泛型 class 用于解析嵌套 Parcelable 泛型字段的加载器
Get generics class loader for parsing nested Parcelable generic field
我有一个 Parcelable
通用类型的包装器,但是 Parcel
构造编译失败,因为 T
class 不能被通用地确定
class MyItem<T : Parcelable> (val model: T) : Parcelable {
constructor(parcel: Parcel) :
this(parcel.readParcelable(T::class.java.classLoader)) {
}
}
这种情况有什么解决办法吗?
您可以使用 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}")
}
如果您需要有一个 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}")
}
为了了解全貌,我最终得到的是:
用例是一个有一个 Parcelable
通用实例,我们称它为 model
,它应该使用 Parcelable
包装器的通用属性来完成,以免外部污染模型领域。例如 Item
包装器。
在下面的示例中,包装器 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 如:
class BasePagerFragment<T : Parcelable> : Fragment(){
protected fun readBundle(bundle: Bundle?) {
bundle.getParcelableArrayList<Item<T>>("items")
}
}
我有一个 Parcelable
通用类型的包装器,但是 Parcel
构造编译失败,因为 T
class 不能被通用地确定
class MyItem<T : Parcelable> (val model: T) : Parcelable {
constructor(parcel: Parcel) :
this(parcel.readParcelable(T::class.java.classLoader)) {
}
}
这种情况有什么解决办法吗?
您可以使用 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}")
}
如果您需要有一个 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}")
}
为了了解全貌,我最终得到的是:
用例是一个有一个 Parcelable
通用实例,我们称它为 model
,它应该使用 Parcelable
包装器的通用属性来完成,以免外部污染模型领域。例如 Item
包装器。
在下面的示例中,包装器 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 如:
class BasePagerFragment<T : Parcelable> : Fragment(){
protected fun readBundle(bundle: Bundle?) {
bundle.getParcelableArrayList<Item<T>>("items")
}
}