简体   繁体   中英

How to fix 'java.lang.InstantiationError' with kotlin enum in Android

I'm trying to start a new kotlin activity from a legacy java activity in Android, and need to pass an enum (defined in kotlin) as an intent extra. From the first (java) activity, I can see the intent extra, but from the second (kotlin) activity, the app crashes because the intent extra is gone. Is there a way to pass the enum directly, or do I have to revert to passing the enum's name or ordinal?

Please note that there is no error if the enum class does not contain any abstract functions of its own (in this case, getTitle() ). However, I need to keep these functions.

MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                IntentExtension.putParcelableExtra(intent, "test", TestEnum.TWO);
                startActivityForResult(intent, 42);
            }
        });
    }
}

SecondActivity.kt

@Parcelize
enum class TestEnum : Parcelable {
    ONE {
        override fun getTitle(): String = "Title One!"
    },

    TWO {
        override fun getTitle(): String = "Title Two!"
    };

    abstract fun getTitle(): String
}

class SecondActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_second)
        val extra = intent.getParcelableExtra<TestEnum>("test") // crash here
        welcomeText.text = getString(R.string.message, extra.name)
    }
}

IntentExtension.kt

@file:JvmName("IntentExtension")

fun Intent.putParcelableExtra(key: String, value: Parcelable) {
    this.putExtra(key, value)
}

Error Log

    java.lang.InstantiationError: com.example.myapplication.TestEnum
        at com.example.myapplication.TestEnum$Creator.createFromParcel(Unknown Source:5)
        at android.os.Parcel.readParcelable(Parcel.java:2782)
        at android.os.Parcel.readValue(Parcel.java:2676)
        at android.os.Parcel.readArrayMapInternal(Parcel.java:3043)
        at android.os.BaseBundle.unparcel(BaseBundle.java:257)
        at android.os.Bundle.getParcelable(Bundle.java:888)
        at android.content.Intent.getParcelableExtra(Intent.java:7075)
        at com.example.myapplication.SecondActivity.onCreate(SecondActivity.kt:27)
        at android.app.Activity.performCreate(Activity.java:6975)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
        at android.app.ActivityThread.-wrap11(Unknown Source:0)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
        at android.os.Handler.dispatchMessage(Handler.java:105)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6541)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)

It seems that kotlin annotation processor can't generate right code for enum parcelization. Write your own code like this:

enum class TestEnum : Parcelable {
    ONE {
        override fun getTitle(): String = "Title One!"
    },

    TWO {
        override fun getTitle(): String = "Title Two!"
    };

    abstract fun getTitle(): String

    override fun describeContents(): Int {
        return 0
    }

    override fun writeToParcel(dest: Parcel?, flags: Int) {
        dest!!.writeInt(ordinal)
    }

    companion object CREATOR : Parcelable.Creator<TestEnum> {
        override fun createFromParcel(parcel: Parcel): TestEnum {
            return values()[parcel.readInt()]
        }

        override fun newArray(size: Int): Array<TestEnum?> {
            return newArray(size)
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM