getParcelableArrayListExtra 会导致将不同的类型设置为变量

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

问题始于

getParcelableArrayListExtra
当我们尝试将其设置为变量时不支持类型检查。让我尽可能举一个基本的例子。

用户类。

import kotlinx.parcelize.Parcelize
import android.os.Parcelable

    @Parcelize
    data class UserClass(
            var name: String? = null,
            var text: String? = null,
            var age: Int? = null
    ) : Parcelable

我们将尝试设置为 User 变量的随机类。

import android.os.Parcelable
import kotlinx.parcelize.Parcelize

@Parcelize
data class MessageClass(
    val title: String?, = Constant.STRING_EMPTY
    val text: String? = Constant.STRING_EMPTY
) : Parcelable

充满意图的课程

class FillIntentClass(){

    //Let's say one of the developers added the MessageClass object inside our intent.
    //Or BE sent the wrong type of object and I passed its value to the intent.
    private fun DummyFunctionToSetIntent(){

    val messageList = arraylistOf(MessageClass(title = "hello",text ="dummy text")

    intent.putParcelableArrayListExtra(EXTRA_PAYMENT_OPTIONS_EXTRA, messageList)
  }   
}

测试课

class MyTestClass(){
  // UserList variable 
   private var mUserList: ArrayList<UserClass>? = null



   override fun onCreate(savedInstanceState: Bundle?) {
        ...
     with(intent) {
     // In this situation, mUserList became the type of ArrayList<MessageClass>
     // But it shouldn't be possible. Because it must accept only ArrayList<UserClass>
     // And that causes mostly crashes when the other code parts use it.
     mUserList = getParcelableArrayListExtra(EXTRA_PAYMENT_OPTIONS_EXTRA)
     // mUserList now pretend its like ArrayList<MessageClass>. But i set it as ArrayList<UserClass> at the top of the class.

     // The best way to solve this is to type check with as?. If the type is not as expected it must return null.
     // But I cannot use type check here. It gives me a "Not enough information to infer type variable T" error.
     mUserList = getParcelableArrayListExtra(EXTRA_PAYMENT_OPTIONS_EXTRA) as? ArrayList<UserClass> //(compile error here on IDE)

     // So I had to come out with the below solution. But I cannot say it's the best practice.
     if (getParcelableArrayListExtra<UserClass>(EXTRA_PAYMENT_OPTIONS_EXTRA)
            ?.filterIsInstance<UserClass>()?.isNotEmpty() == true
    ) {
        mUserList = getParcelableArrayListExtra(EXTRA_PAYMENT_OPTIONS_EXTRA)
      }
    }
  }
}

类型检查(as,as?)按预期与

getParcelable
函数一起使用。但是当涉及到
getParcelableArrayListExtra
时,它就不起作用并给出编译错误,正如我上面所解释的。

您知道什么是

as, as?
检查的最佳选择吗?
mUserList
如何接受不同类型的数组并假装喜欢它?

android android-intent parcelable parcel
3个回答
0
投票

由于以下几个原因,这是一团糟:

  • 您正在使用 Kotlin 进行编码,但您正在处理的类(
    Parcelable
    Bundle
    Intent
    ArrayList
    )实际上是 Java
  • Java 中的泛型是一种 hack

我会把问题分成两部分:

  1. ArrayList
    解包为
    ArrayList<Parcelable>
  2. 检查/转换
    ArrayList<Parcelable>
    的内容为期望的类型

0
投票

检查 API 级别和相应的代码:

  if (Build.VERSION.SDK_INT >= 33) { 
    data = intent.getParcelableExtra (String name, Class<T> clazz)
}else{
    data = intent.getParcelableExtra("data")
}

您还可以将这些扩展用于捆绑和意图:

inline fun <reified T : Parcelable> Intent.parcelable(key: String): T? = when {
  SDK_INT >= 33 -> getParcelableExtra(key, T::class.java)
  else -> @Suppress("DEPRECATION") getParcelableExtra(key) as? T
}

inline fun <reified T : Parcelable> Bundle.parcelable(key: String): T? = when {
  SDK_INT >= 33 -> getParcelable(key, T::class.java)
  else -> @Suppress("DEPRECATION") getParcelable(key) as? T
}

0
投票

您不需要将 ParcelableArrayList 转换为 ArrayList,而是在检索它时使用 ArrayList 创建它,就像发出额外内容一样:

mUserList = ArrayList<UserClass>(getParcelableArrayListExtra(EXTRA_PAYMENT_OPTIONS_EXTRA))
© www.soinside.com 2019 - 2024. All rights reserved.