Android中关于Activity中传递数据

gkh 发布于 2022-01-25 6183 次阅读


最近想继续自己之前的梦想,入了安卓编程的坑项目问题等做完了慢慢复盘,先总结今天遇到的难题。如何在Activity中传递数据。对于简单的数据而言可以直接通过putExtra来进行数据传送

val data = "Hello SecondActivity"
val intent = Intent(this, SecondActivity::class.java)
intent.putExtra("extra_data", data)
startActivity(intent)

但是对于复杂的数据结构而言 putExtra方法就不存在重构方法了,需要自己完成。通过查阅资料发现大家都在采用Parcelable的管道符来进行数据传输的。每个Activity相当于独立的存在,本身的数据通信只能在内存中另外开辟一段空间让Intet类携带数据跑到另一个Activity中。如何使用Parcelable管道方法呢。目前我的数据结构是这样的

class Fridge(val name: String? ="", val location:String?="", val time:String?="")
class SearchJson(val response:Int, var data: List<Fridge>)

本身SearchJson是用来接收json返回的数据用的,这里本身数据主要是后面的data部分所以就全部传递了。直接使用putExtra是无法传递的。本身没有重载这个方法,尝试使用ArrayList结构也不行,拷贝时会直接闪退。虽然说是继承关系,但是还是不能直接拷贝。所以就采用Parcelable方法传递,这个方法相当于把整个结构进行了流式排列,将整个结构按照一定顺序压入队列然后进行线性发送,所以把这个类作为父类,然后就需要重载五个函数

constructor(parcel: Parcel) :this
override fun writeToParcel(p0: Parcel?, p1: Int)
 override fun describeContents(): Int
 companion object CREATOR : Parcelable.Creator<SearchJson> {
        override fun createFromParcel(parcel: Parcel): SearchJson {
            return SearchJson(parcel)
        }

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

这五个方法主要功能是前两个分别是反序列化和序列化。简单来说就是打包函数和解压函数如果只是简单元素,IDE会帮你自动补全的,基本不用操心,但是有列表就需要自己写一下,这里我也是初上手试图解决一下这几个问题
parcel提供了序列化(writexxx)和反序列化(readxxx)来进行操作。一般的如writeint就可以把int型写入。如果涉及到list型也可以直接使用writelist 不过这里主意,对于list是其他类的列表,其他类也需要继承Parcelable类写相应的序列化和反序列化函数来帮助打包。

override fun writeToParcel(p0: Parcel?, p1: Int) {
        p0?.writeInt(response)
        if(data.isNotEmpty())
        {
            p0?.writeInt(data.size)
            p0?.writeList(data)
        }

        else
        {
            p0?.writeInt(0)
        }

这边是我写的打包函数,对于data而言本身是List型,只需要把Fridge也做相应处理即可

override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeString(name)
        parcel.writeString(location)
        parcel.writeString(time)
    }

这样打包部分就结束了

接下来是 反序列化部分。当进入后进行解包先贴代码

constructor(parcel: Parcel) : this(response=parcel.readInt(),data= ArrayList<Fridge>()) {
        if(parcel.readInt()>0)
        {
            parcel.readList(data,Fridge.javaClass.classLoader)
        }

    }

我这里主要是加了个校验如果不加校验也是可以的。在this指针部分先对类的变量进行初始化。然后再赋值,如果是基础类型如response可以直接赋值 parcel.readInt() 对于复杂类型先初始化ArrayList 注意ArrayList是可变数组,不存在list的初始化操作。下面使用的是readList函数,如果write部分使用writearraylist这里就也要一致。两边不一致会导致解析出错。readlist的两个参数分别是要写入的变量,和list内部的类型。注意第二个参数是 Fridge.javaClass.classLoader

第三部分是外部代码这部分就简单了

                        val intent = Intent(this@SearchActivity,SearchResultActivity::class.java)
                        intent.putExtra("fridge_list",list)
                        startActivity(intent)

这部分跟一般的没什么不一样 有个小细节 java语言的this指针是类。写作searchActivity.this` kotlin写作 `this@SearchActivity

 val receive= intent.getParcelableExtra<SearchJson>("fridge_list")
        val list= receive?.data

这部分使用Parcelable函数来进行解析注意类型名称。
PS:现学现卖还是有点难度的
参考
https://stackoverflow.com/questions/6300608/how-to-pass-a-parcelable-object-that-contains-a-list-of-objects
https://developer.android.com/reference/android/os/Parcel#readList(java.util.List,%20java.lang.ClassLoader)
https://medium.com/the-lazy-coders-journal/easy-parcelable-in-kotlin-the-lazy-coders-way-9683122f4c00

区别SerializableParcelable
所属API不同属于Java API属于 Android SDK
原理不同Serializable 序列化和反序列化需要大量的I/O操作Parcleable序列化和反序列化不需要大量的I/O操作
开销不同开销大开销小
效率不同效率低效率高
使用场景不同Serializable序列化到本地或者网络传输Parcleable是内存序列化