添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

The problem starts with getParcelableArrayListExtra doesn't support type check when we try to set it to a variable. Let me give an example as basic as I can.

A User Class.

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

The random class which we'll try to set to the User variable.

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

The class that fills intent

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)

Test class

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?) works with getParcelable functions as expected. But when it comes to the getParcelableArrayListExtra it just doesn't work and gives compile error as I explained above.

Do you have any knowledge of what's the best option for as, as? check? And how it's possible for mUserList to accept a different type of Array and pretend like it?

You aren't calling getParcelableArrayListExtra() on an Intent here. Have you implemented your own getParcelableArrayListExtra() method? Please put the code for that into the question. – David Wasser Aug 8, 2022 at 10:39

This is a mess for a few reasons:

  • You are coding in Kotlin, but the classes you are dealing with (Parcelable, Bundle, Intent, ArrayList) are actually Java
  • Generics in Java are a hack
  • I would split the problem into 2 parts:

  • Unparcel the ArrayList into ArrayList<Parcelable>
  • Check/convert the contents of the ArrayList<Parcelable> into the expected type
  • Check the API level and code accordingly:

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

    Also you can use these extensions for bundle and intent:

    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
            

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.