【问题标题】:getParcelableArrayListExtra causes a different type to be set to a variablegetParcelableArrayListExtra 导致将不同的类型设置为变量
【发布时间】:2022-12-28 15:49:40
【问题描述】:

问题以 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)
      }
    }
  }
}

Type check(as,as?) 按预期与 getParcelable 函数一起使用。但是,当涉及到 getParcelableArrayListExtra 时,它就不起作用,并且会出现编译错误,正如我上面所解释的那样。

您是否知道 as, as? 支票的最佳选择是什么? mUserList 怎么可能接受不同类型的数组并假装喜欢它?

【问题讨论】:

  • 你不是在这里通过 Intent 呼叫 getParcelableArrayListExtra()。你实现了自己的getParcelableArrayListExtra()方法了吗?请将代码放入问题中。
  • 是的,代码块外有 with(intent) {}。让我编辑我的帖子

标签: android android-intent parcelable parcel


【解决方案1】:

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

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

我会把问题分成两部分:

  1. ArrayList解包为ArrayList&lt;Parcelable&gt;
  2. 检查/转换 ArrayList&lt;Parcelable&gt; 的内容为预期类型

【讨论】:

    【解决方案2】:

    相应地检查 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
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-22
      • 2019-02-11
      • 1970-01-01
      • 2022-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多