Android开发-Intent使用Serializable和Parcelable方式传递数据

2023-11-01

前 言

在Android中一个Activity跳转至另一个Activity或者启动Service、发送广播等都需要Intent,可以说Intent在Android中用途比较广泛,我们还可以通过Intent在跳转至下一个界面或者启动另一个组件时携带一些数据进行传递到下一个界面或者组件已达到传值的效果。不过在通常通过Intent传值都是传递一些某些具体类型的数据。具体代码如下:

Intent intent = new Intent(this,SecondActivity.class);
intent.putExtra("name","_彼岸雨敲窗_");
intent.putExtra("age",25);
intent.putExtra("isBoy",true);
startActivity(intent);

这里通过Intent的putExtra()方法来添加具体类型(比如String、Int以及Boolean类型等)的数据,然后在SecondActivity接收传递过来的数据。具体代码如下:

getIntent().getStringExtra("name");
getIntent().getIntExtra("age", 0);
getIntent().getBooleanExtra("isBoy", true);

可以看到这种传值方式非常方便,但是也有一定的局限性,比如传递数据的类型比较多或者传递的数据量比较大的时候这种方式传递数据不是最优的选择。那么,有没有最优的传递复杂的数据类型的方式呢?还真有,可以通过自定义对象的方式,然后通过Serializable和Parcelable方式进行传递数据。下面就来看看如何在Intent中使用这两种方式进行传递数据吧。

使用Serializable方式

Serializable是序列化的意思,它表示将对象状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它将流转换为对象。这两个过程结合起来,可以轻松地存储和传输数据。如何让对象进行序列化呢?只需要在创建的对象类实现Serializable这个接口就可以了。代码如下:

public class Programmer implements Serializable {

    private static final long serialVersionUID = 1L;
    
    private String name;
    private int age;
    private boolean boy;

    // set 和 get 略
}

可以看到我们在Programmer类实现了Serializable的接口,Programmer类中的所有对象都可以实现了可序列化了。

然后在Intent传递数据时可以这样写,代码如下:

Intent intent = new Intent(this, SecondActivity.class);
Programmer programmer = new Programmer();
programmer.setName("_彼岸雨敲窗_");
programmer.setAge(25);
programmer.setBoy(true);
intent.putExtra("programmer_data", programmer);
startActivity(intent);

可以看到,这里还是使用Intent中的putExtra()方法来添加数据,不过这里不是添加某具体类型的数据,而是添加已经被序列化过实例对象的数据。

然后接下来在SecondActivity中获取传递过来的对象数据,代码如下:

Programmer programmer = (Programmer) getIntent().getSerializableExtra("programmer_data");
if (programmer != null) {
     String name = programmer.getName();
     int age = programmer.getAge();
     boolean isBoy = programmer.isBoy();
}

可以看到这里取得数据使用的是getSerializableExtra()方法,该方法的作用就是通过传递过来的序列化对象强转成Programmer对象,然后调用对象的get()方法取出相应的数值。

Intent使用Serializable方式传递数据的原理:首先先将一个对象序列化成一个可以储存或者可以传输的状态,然后传递下一个界面时通过反序列化成一个新的对象,最后通过新的对象进行取值操作。

使用Parcelable方式

Parcelable是Android系统中特有的接口,它不像Serializable接口那样是Java语言自带的。Intent也使用Parcelable方式来传递对象的数据,不过它不同于Serializable方式将对象进行序列化,而是通过将一个完整的对象进行分解,而分解后的每一部分都是Intent所支持的传递数据类型。下面我们就来看看如何实现这个方式的数据传递,首先先创建一个对象,代码如下:

public class Programmer implements Parcelable {

    private String name;
    private int age;
    private boolean boy;

    protected Programmer(Parcel in) {
        name = in.readString();
        age = in.readInt();
        boy = in.readByte() != 0;
    }

    public static final Creator<Programmer> CREATOR = new Creator<Programmer>() {
        @Override
        public Programmer createFromParcel(Parcel in) {
            return new Programmer(in);
        }

        @Override
        public Programmer[] newArray(int size) {
            return new Programmer[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel parcel, int i) {
        parcel.writeString(name);
        parcel.writeInt(age);
        parcel.writeByte((byte) (boy ? 1 : 0));
    }

    // set 和 get 略
 
}

从代码中可以看出,Parcelable实现的方式相对于Serializable要复杂一点,首先先让Programmer对象实现了Parcelable接口,然后重写describeContents()和writeToParcel()方法,其中describeContents()方法直接返回0就可以了,而writeToParcel()中我们需要调用Parcel对象的writeXX()方法依次把字段写入。除了这两个方法之外,我们还要实现一个名为CREATOR的匿名内部类,在这里创建了Programmer.Creator的泛型接口,并将泛型类型设为Programmer,接着在该接口重写createFromParcel()和newArray()方法,而在createFromParcel()方法中,
我们需要创建Programmer对象进行返回,并使用Parcel对象的readXX()方法读取刚才在writeToParcel()写入的字段,需要注意的是,这里读取的顺序一定和刚才写入的顺序相同。而在newArray()方法中需要实现就比较简单了,只需要直接返回Programmer对象数组大小即可。

然后在Intent传递数据时可以这样写,代码如下:

Intent intent = new Intent(this, SecondActivity.class);
Programmer programmer = new Programmer();
programmer.setName("_彼岸雨敲窗_");
programmer.setAge(25);
programmer.setBoy(true);
intent.putExtra("programmer_data", programmer);
startActivity(intent);

可以看到,这里还是使用Intent中的putExtra()方法来添加数据。

然后接下来在SecondActivity中获取传递过来的对象数据,代码如下:

Programmer programmer = (Programmer) getIntent().getParcelableExtra("programmer_data");
if (programmer != null) {
     String name = programmer.getName();
     int age = programmer.getAge();
     boolean isBoy = programmer.isBoy();
}

可以看到这里取得数据使用的是getParcelableExtra()方法来获取传递过来的Programmer对象,然后调用对象的get()方法取出相应的数值。

Serializable和Parcelable方式传递数据的优缺点
  • Parcelable相对于Serializable的使用相对复杂一些;

  • Parcelable的传输效率相对Serializable高很多;

  • Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable在外界有变化的情况下不能很好的保证数据的持续性。尽管Serializable效率低点,但此时还是建议使用Serializable。

附:Intent为什么不能传递较大的数据

Intent携带信息的大小其实是受Binder限制。数据以Parcel对象的形式存放在Binder传递缓存中。如果数据或返回值比传递buffer大,则此次传递调用失败并抛出TransactionTooLargeException异常。Binder传递缓存有一个限定大小,通常是1Mb。但同一个进程中所有的传输共享缓存空间。多个地方在进行传输时,即时它们各自传输的数据不超出大小限制,TransactionTooLargeException异常也可能会被抛出。在使用Intent传递数据时,1Mb并不是安全上限。因为Binder中可能正在处理其它的传输工作。不同的Android设备和系统版本,这个上限值也可能会不同。

如果是要传递较大的数据的话,建议使用EventBus来代替Intent传递较大的数据。

———————— The end ————————

码字不易,如果您觉得这篇博客写的比较好的话,可以赞赏一杯咖啡吧~~
在这里插入图片描述


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android开发-Intent使用Serializable和Parcelable方式传递数据 的相关文章

  • 路径中 File.separator 和斜杠之间的区别

    使用有什么区别File separator和一个正常的 在 Java 路径字符串中 与双反斜杠相反 平台独立性似乎不是原因 因为两个版本都可以在 Windows 和 Unix 下运行 public class SlashTest Test
  • 在两个活动之间传输数据[重复]

    这个问题在这里已经有答案了 我正在尝试在两个不同的活动之间发送和接收数据 我在这个网站上看到了一些其他问题 但没有任何问题涉及保留头等舱的状态 例如 如果我想从 A 类发送一个整数 X 到 B 类 然后对整数 X 进行一些操作 然后将其发送
  • 为什么HashMap不能保证map的顺序随着时间的推移保持不变

    我在这里阅读有关 Hashmap 和 Hashtable 之间的区别 http javarevisited blogspot sg 2010 10 difference Between hashmap and html http javar
  • 字符串数组文本格式化

    我有这个字符串 String text Address 1 Street nr 45 Address 2 Street nr 67 Address 3 Street nr 56 n Phone number 000000000 稍后将被使用
  • JRE 系统库 [WebSphere v6.1 JRE](未绑定)

    将项目导入 Eclipse 后 我的构建路径中出现以下错误 JRE System Library WebSphere v6 1 JRE unbound 谁知道怎么修它 右键单击项目 特性 gt Java 构建路径 gt 图书馆 gt JRE
  • 错误:在根项目“projectName”中找不到项目“app”

    我有一个在 Eclipse 中开发的旧应用程序 现在尝试将其迁移到 Android Studio 我更新了库并遵循了基本步骤 现在 我收到此错误 Error Project app not found in root project pro
  • 如何在控制器、服务和存储库模式中使用 DTO

    我正在遵循控制器 服务和存储库模式 我只是想知道 DTO 在哪里出现 控制器应该只接收 DTO 吗 我的理解是您不希望外界了解底层域模型 从领域模型到 DTO 的转换应该发生在控制器层还是服务层 在今天使用 Spring MVC 和交互式
  • Eclipse Java 远程调试器通过 VPN 速度极慢

    我有时被迫离开办公室工作 这意味着我需要通过 VPN 进入我的实验室 我注意到在这种情况下使用 Eclipse 进行远程调试速度非常慢 速度慢到调试器需要 5 7 分钟才能连接到远程 jvm 连接后 每次单步执行断点 行可能需要 20 30
  • 我的设备突然没有显示在“Android 设备选择器”中

    我正在使用我的三星 Galaxy3 设备来测试过去两个月的应用程序 它运行良好 但从今天早上开始 当我将设备连接到系统时 它突然没有显示在 Android 设备选择器 窗口中 我检查过 USB 调试模式仅在我的设备中处于选中状态 谁能猜出问
  • 如何从指定日期获取上周五的日期? [复制]

    这个问题在这里已经有答案了 如何找出上一个 上一个 星期五 或指定日期的任何其他日期的日期 public getDateOnDay Date date String dayName 我不会给出答案 先自己尝试一下 但是 也许这些提示可以帮助
  • .isProviderEnabled(LocationManager.NETWORK_PROVIDER) 在 Android 中始终为 true

    我不知道为什么 但我的变量isNetowrkEnabled总是返回 true 我的设备上是否启用互联网并不重要 这是我的GPSTracker class public class GPSTracker extends Service imp
  • 如何根据 gradle 风格设置变量

    我想传递一个变量test我为每种风格设置了不同的值作为 NDK 的定义 但出于某种原因 他总是忽略了最后味道的价值 这是 build gradle apply plugin com android library def test andr
  • Android 套接字和 asynctask

    我即将开始制作一个应该充当 tcp 聊天客户端的应用程序 我一直在阅读和阅读 我得出的结论是最好 如果不需要 将我的套接字和异步任务中的阅读器 问题是我不确定从哪里开始 因为我是 Android 新手 这至少对我来说是一项艰巨的任务 但据我
  • 获取 JVM 上所有引导类的列表?

    有一种方法叫做findBootstrapClass对于一个类加载器 如果它是引导的 则返回一个类 有没有办法找到类已经加载了 您可以尝试首先通过例如获取引导类加载器呼叫 ClassLoader bootstrapLoader ClassLo
  • 静态变量的线程安全

    class ABC implements Runnable private static int a private static int b public void run 我有一个如上所述的 Java 类 我有这个类的多个线程 在里面r
  • 编译器抱怨“缺少返回语句”,即使不可能达到缺少返回语句的条件

    在下面的方法中 编译器抱怨缺少退货声明即使该方法只有一条路径 并且它包含一个return陈述 抑制错误需要另一个return陈述 public int foo if true return 5 鉴于Java编译器可以识别无限循环 https
  • 如何在Xamarin中删除ViewTreeObserver?

    假设我需要获取并设置视图的高度 在 Android 中 众所周知 只有在绘制视图之后才能获取视图高度 如果您使用 Java 有很多答案 最著名的方法之一如下 取自这个答案 https stackoverflow com a 24035591
  • 实现滚动选择 ListView 中的项目

    我想使用 ListView 您可以在其中滚动列表来选择一个项目 它应该像一个 Seekbar 但拇指应该是固定的 并且您必须使用该栏来调整它 我面临的一个问题是 我不知道这种小部件是如何调用的 这使得我很难搜索 所以我制作了下面这张图片 以
  • JGit 检查分支是否已签出

    我正在使用 JGit 开发一个项目 我设法删除了一个分支 但我还想检查该分支是否已签出 我发现了一个变量CheckoutCommand但它是私有的 private boolean isCheckoutIndex return startCo
  • android sdk 的位置尚未在 Windows 操作系统的首选项中设置

    在 Eclipse 上 我转到 windows gt Android SDK 和 AVD Manager 然后弹出此消息 Android sdk 的位置尚未在首选项中设置 进入首选项 在侧边栏找到 Android 然后会出现一个 SDK 位

随机推荐