邵鹏飛 發表於 2025-7-21 08:30:33

Android通过Intent传递自定义对象的两种方式

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>前言</li><li>方式一:Serializable</li><li>方式二:Parcelable</li><li>对比</li></ul></div><p class="maodian"></p><h2>前言</h2>
<p>我们经常会使用 <code>Intent</code> 来启动 <code>Activity</code>、发送广播等。在进行上述操作的过程中,我们还可以往 <code>Intent</code> 对象中添加额外的数据,比如:</p>
<div class="jb51code"><pre class="brush:java;">// MainActivity.kt
val intent = Intent(this, AnotherActivity::class.java)
intent.putExtra("name", "Martin")
intent.putExtra("age", 21)
startActivity(intent)
</pre></div>
<p>以此来完成数据的传递:</p>
<div class="jb51code"><pre class="brush:java;">// AnotherActivity.kt
val name = intent.getStringExtra("name") ?: "Unknown Name"
val age = intent.getIntExtra("age", -1)
</pre></div>
<p>但问题在于 <code>putExtra</code> 可传递的数据类型是有限的,如果你想传递自定义对象,就<strong>行不通</strong>了。但请别担心,我们接下来就来学习如何通过 <code>Intent</code> 传递自定义对象。</p>
<p class="maodian"></p><h2>方式一:Serializable</h2>
<p><code>Serializable</code> 翻译过来是序列化的意思,表示将一个对象转换为可存储或可传输的状态,序列化后的对象可被存储到本地,也可在网络上进行传输。</p>
<p>序列化一个类,其实非常简单,只需让这个类实现 <code>Serializable</code> 接口即可。例如:</p>
<div class="jb51code"><pre class="brush:java;">class Person : Serializable {
    var name = ""
    var age = 0
}
</pre></div>
<p>这样,所有的 <code>Person</code> 对象都是可序列化的了。现在,我们想要传递一个 <code>Person</code> 对象,只需这样:</p>
<div class="jb51code"><pre class="brush:java;">val person = Person()
person.name = "Jack"
person.age = 21
val intent = Intent(this, AnotherActivity::class.java)
intent.putExtra("person", person)
startActivity(intent)
</pre></div>
<p>那么,该怎么从 <code>Intent</code> 中取出这个 <code>Person</code> 对象呢?</p>
<p>答案是使用 <code>getSerializableExtra()</code> 方法获取序列化对象,再向下转型为 <code>Person</code> 对象即可。</p>
<div class="jb51code"><pre class="brush:java;">// val person_from_intent: Person = intent.getSerializableExtra("person") as Person
</pre></div>
<p>不过,这个方法已经被废弃了。原因在于它不能保证<strong>类型安全</strong>,如果获取到的不是 <code>Person</code> 类型的对象,又或是键名拼写错误导致返回 <code>null</code>,那么在运行时,<code>as</code> 强制类型转换可能会失败并导致程序崩溃。</p>
<p>所以,现在我们会使用<strong>更安全</strong>的重载方法 <code>getSerializableExtra(String, Class&lt;T&gt;)</code>。这个方法是在 Android 13 (API 33) 引入的,为了兼容所有版本,我们需要这样写:</p>
<div class="jb51code"><pre class="brush:java;">val person: Person? = if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.TIRAMISU) {
    intent.getSerializableExtra("person", Person::class.java)
} else {
    // 使用 as? 安全转型来避免崩溃
    @Suppress("DEPRECATION")
    intent.getSerializableExtra("person") as? Person
}
</pre></div>
<p>这样,我们就成功实现了通过 <code>Intent</code> 来传递自定义对象。</p>
<p>最后注意一点:在这个过程中,会将对象序列化为可存储或可传输的状态,再将其反序列化为一个新的对象。虽然这两个对象存储的数据一致,但其实是两个不相同的对象。</p>
<p class="maodian"></p><h2>方式二:Parcelable</h2>
<p>我们也可以通过 <code>Parcelable</code> 来完成。只不过它的实现原理是将完整的对象进行分解,使得分解后的每一个部分都是 Intent 所支持的数据类型,这样也能实现通过 <code>Intent</code> 来传递自定义对象的功能。</p>
<p>如果使用 <code>Parcelable</code> 的实现方式,<code>Person</code> 类的代码将会是这样的:</p>
<div class="jb51code"><pre class="brush:java;">class Person(var name: String?, var age: Int) : Parcelable {

    constructor(parcel: Parcel) : this(
      parcel.readString(),
      parcel.readInt()
    )

    override fun writeToParcel(parcel: Parcel, flags: Int) {
      // 将当前类中的字段写出
      parcel.writeString(name)
      parcel.writeInt(age)
    }

    override fun describeContents(): Int {
      return 0
    }
   
    // 注意:读取字段的顺序需要和写出字段的顺序保持一致。
    companion object CREATOR : Parcelable.Creator&lt;Person&gt; {
      override fun createFromParcel(parcel: Parcel): Person {
            return Person(parcel)
      }

      override fun newArray(size: Int): Array&lt;Person?&gt; {
            return arrayOfNulls(size)
      }
    }
}
</pre></div>
<p>可以看到,手动编写这些模版代码非常繁琐。为此,Kotlin 提供了一种更加简便的用法。</p>
<p>我们先在 <code>app/build.gradle.kts</code> 文件中添加插件依赖:</p>
<div class="jb51code"><pre class="brush:java;">plugins {
    id("kotlin-parcelize")
}
</pre></div>
<p>然后,修改 <code>Person</code> 类:</p>
<div class="jb51code"><pre class="brush:java;">import kotlinx.parcelize.Parcelize

@Parcelize
data class Person(var name: String, var age: Int) : Parcelable
</pre></div>
<p>只需加上一个 <code>@Parcelize</code> 注解,就可以省去了一大堆模板代码的麻烦。</p>
<blockquote><p>注意:使用 @Parcelize 时,所有要传递的数据都必须在类的主构造函数中声明。</p></blockquote>
<p>接下来,在获取 <code>Intent</code> 中的数据时,只需使用 <code>getParcelableExtra()</code> 方法即可。同样地,需要处理版本兼容问题:</p>
<div class="jb51code"><pre class="brush:java;">val person: Person? = if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.TIRAMISU) {
    intent.getParcelableExtra("person", Person::class.java)
} else {
    @Suppress("DEPRECATION")
    intent.getParcelableExtra&lt;Person&gt;("person")
}
</pre></div>
<p class="maodian"></p><h2>对比</h2>
<p>对比 <code>Serializable</code> 和 <code>Parcelable</code> 这两种方式,<code>Serializable</code> 的实现非常简单,但它序列化时会用到<strong>反射</strong>,导致性能开销大。<code>Parcelable</code> 则通过显式的读写操作来分解对象,没有反射的开销,效率要高得多。</p>
<p>因此,在安卓开发中,通常情况下,我们都会选择使用 <code>Parcelable</code> 的方式。</p>
<p>以上就是Android通过Intent传递自定义对象的两种方式的详细内容,更多关于Android Intent传递自定义对象的资料请关注琼殿技术社区其它相关文章!</p>
                           
                            <div class="art_xg">
                              <b>您可能感兴趣的文章:</b><ul><li>Android编程实现全局获取Context及使用Intent传递对象的方法详解</li><li>Android Intent传递对象的两种方法(Serializable,Parcelable)详细介绍</li><li>Android 通过Intent使用Bundle传递对象详细介绍</li><li>在Android中通过Intent使用Bundle传递对象的使用方法</li><li>Android中Intent传递对象的3种方式详解</li></ul>
                            </div>

                        </div>
                        <!--endmain-->
頁: [1]
查看完整版本: Android通过Intent传递自定义对象的两种方式