大家都知道想要在Activity之间传递对象数据时可以通过实现Parcelable,在java代码中,我们一般用Android Studio插件(Android Parcelable code generator)来生成Parcelable需要的代码,但是在kotlin代码中不需要使用第三方插件,Android Studio自带编辑器就可以自动生成kotlin代码的Parcelable实现,之前的插件也在kotlin里无法使用,在windows上,我们定位到类名,按ALT+Enter组合键就可以出现一个菜单如下:
选择第一个就会自动帮我们生成Parcelable需要的代码如下图所示:
class DemoBean() :Parcelable{
var name: String? = null
var images: ArrayList<String>? = null
constructor(parcel: Parcel) : this() {
name = parcel.readString()
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(name)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<DemoBean> {
override fun createFromParcel(parcel: Parcel): DemoBean {
return DemoBean(parcel)
}
override fun newArray(size: Int): Array<DemoBean?> {
return arrayOfNulls(size)
}
}
}
回到上面标题遇到的问题:
kotlin 实现了Parcelable但是Activity之间传递时ArrayList的值为什么还是为null?
从上面生成的Parcelable代码可以看到,它并没有为我们的images这个变量生成Parcelable代码实现,这就是为什么在跳转Activity后这个对象的ArrayList对应的变量值都为null的原因。
那么Android Studio为什么不帮我们生成ArrayList的Parcelable代码呢?是不是在kotlin里面ArrayList不能被Parcelable?
于是带着问题,又试了将images类型分别改为:List、MutableList,结果发现只有当定义成List类型的时候,才会自动生成images变量的Parcelable代码,如下:
class DemoBean() : Parcelable {
var name: String? = null
var images: List<String>? = null
constructor(parcel: Parcel) : this() {
name = parcel.readString()
images = parcel.createStringArrayList()//看这里!!!!
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(name)
parcel.writeStringList(images)//看这里!!!!
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<DemoBean> {
override fun createFromParcel(parcel: Parcel): DemoBean {
return DemoBean(parcel)
}
override fun newArray(size: Int): Array<DemoBean?> {
return arrayOfNulls(size)
}
}
}
虽然说在kotlin里,这里定义成List类型也是可以的,因为ArrayList是继承自MutableList,而MutableList是继承自List,但是List里却没有常用的clear、addAll等方法,在使用到这个List的时候需要强制类型转换,不是很方便。
如果定义成ArrayList不会自动生成Parcelable代码,那手动加上行不行呢?于是带着疑问将images类型改为最开始的ArrayList,上面images变量生成的Parcelable代码保持不变,完整代码如下:
class DemoBean() : Parcelable {
var name: String? = null
var images: ArrayList<String>? = null//看这里!!!!
constructor(parcel: Parcel) : this() {
name = parcel.readString()
images = parcel.createStringArrayList()//看这里!!!!
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(name)
parcel.writeStringList(images)//看这里!!!!
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<DemoBean> {
override fun createFromParcel(parcel: Parcel): DemoBean {
return DemoBean(parcel)
}
override fun newArray(size: Int): Array<DemoBean?> {
return arrayOfNulls(size)
}
}
}
试了一下发现ArrayList手动实现Parcelable完全没问题,跳转Activity后数据也能够恢复,所以总结下来那就只能是Android Studio的bug了。
如果手写Parcelable代码实现,则需要注意:
1、如果ArrayList里的对象是String类型的:
class DemoBean() : Parcelable {
var images: ArrayList<String>? = null
constructor(parcel: Parcel) : this() {
images = parcel.createStringArrayList()
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeStringList(images)
}
2、如果ArrayList里的对象是自定义,则该对象也要实现Parcelable:
class DemoBean() : Parcelable {
var images: ArrayList<OtherDataBean>? = null
constructor(parcel: Parcel) : this() {
images = parcel.createTypedArrayList(OtherDataBean.CREATOR)
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeTypedList(images)
}
3、还要注意各个变量的顺序问题,比如变量a和b,在writeToParcel方法里,a在b的前面write,而constructor里b却在a的前面恢复就不行,数据不能被正确恢复
当然还有更简便的方法,但目前只是实验性的功能,纯Kotlin开发还可以,混合开发可能会出现编译不通过找不到CREATOR问题
app的build.gradle里添加如下配置,开启kotlin实验性功能
android{
...
androidExtensions {
experimental = true
}
...
}
然后在类名上面添加@Parcelize注解就可以了,如果出现Link提示则再在上面加上@SuppressLint(“ParcelCreator”)忽略警告
@SuppressLint("ParcelCreator")//这句视情况而定,我这个AS版本没有报错
@Parcelize
class DemoBean() : Parcelable {
var images: ArrayList<OtherDataBean>? = null
}
我的Android Studio版本号是:3.4.2
kotlin版本号是:1.3.41