当前位置:

首页 > 系统应用 > 4.5.2 Intent之复杂数据的传递

4.5.2 Intent之复杂数据的传递

本文目录

    本节引言: 上一节已经把Intent的基础用法过了一遍,包括它的七个属性、显式Intent和隐式Intent的区别、如何自定义隐式Intent,以及一些常用的系统Intent。接下来这部分,重点就落在Intent的数据传递上了。话不多说,直接进入本节内容。 1.Intent传递简单数据 还记得我们在

    本节引言:

    上一节已经把Intent的基础用法过了一遍,包括它的七个属性、显式Intent和隐式Intent的区别、如何自定义隐式Intent,以及一些常用的系统Intent。接下来这部分,重点就落在Intent的数据传递上了。话不多说,直接进入本节内容。

    1.Intent传递简单数据

    还记得我们在Activity那里学过如何在两个Activity中互相传递简单数据的方法吗?

    就是可以直接通过调用Intent的putExtra()方法存入数据,然后在获得Intent后调用getXxxExtra获得 对应类型的数据;传递多个的话,可以使用Bundle对象作为容器,通过调用Bundle的putXxx先将数据 存储到Bundle中,然后调用Intent的putExtras()方法将Bundle存入Intent中,然后获得Intent以后, 调用getExtras()获得Bundle容器,然后调用其getXXX获取对应的数据! 另外数据存储有点类似于Map的<键,值>!

    2.Intent传递数组

    嘿嘿,普通类型倒没问题,但是如果是数组咧?解决方法如下:

    写入数组:

    bd.putStringArray("StringArray", new String[]{"呵呵","哈哈"});
    //可把StringArray换成其他数据类型,比如int,float等等...

    读取数组:

    String[] str = bd.getStringArray("StringArray")

    3.Intent传递集合

    嗯,数组很简单吧,那我们再来传下集合~这个就稍微复杂点了,分情况处理:

    1)List<基本数据类型或String>

    写入集合:

    intent.putStringArrayListExtra(name, value)
    intent.putIntegerArrayListExtra(name, value)

    读取集合:

    intent.getStringArrayListExtra(name)
    intent.getIntegerArrayListExtra(name)

    2)List< Object>

    将list强转成Serializable类型,然后传入(可用Bundle做媒介)

    写入集合:

    putExtras(key, (Serializable)list)

    读取集合:

    (List) getIntent().getSerializable(key)
    
    

    PS:Object类需要实现Serializable接口

    3)Map,或更复杂的

    解决方法是:外层套个List

    //传递复杂些的参数 
    Map map1 = new HashMap();  
    map1.put("key1", "value1");  
    map1.put("key2", "value2");  
    List> list = new ArrayList>();  
    list.add(map1);  
    Intent intent = new Intent();  
    intent.setClass(MainActivity.this,ComplexActivity.class);  
    Bundle bundle = new Bundle();  
    //须定义一个list用于在budnle中传递需要传递的ArrayList,这个是必须要的  
    ArrayList bundlelist = new ArrayList();   
    bundlelist.add(list);   
    bundle.putParcelableArrayList("list",bundlelist);  
    intent.putExtras(bundle);                
    startActivity(intent); 
    

    4.Intent传递对象

    传递对象的方式有两种:将对象转换为Json字符串或者通过Serializable,Parcelable序列化 不建议使用Android内置的抠脚Json解析器,可使用fastjson或者Gson第三方库!

    1)将对象转换为Json字符串

    Gson解析的例子:

    Model:

    public class Book{
        private int id;
        private String title;
        //...
    }
    public class Author{
        private int id;
        private String name;
        //...
    }

    写入数据:

    Book book=new Book();
    book.setTitle("Ja va编程思想");
    Author author=new Author();
    author.setId(1);
    author.setName("Bruce Eckel");
    book.setAuthor(author);
    Intent intent=new Intent(this,SecondActivity.class);
    intent.putExtra("book",new Gson().toJson(book));
    startActivity(intent);

    读取数据:

    String bookJson=getIntent().getStringExtra("book");
    Book book=new Gson().fromJson(bookJson,Book.class);
    Log.d(TAG,"book title->"+book.getTitle());
    Log.d(TAG,"book author name->"+book.getAuthor().getName());

    2)使用Serializable,Parcelable序列化对象

    1.Serializable实现:

    ①业务Bean实现:Serializable接口,写上getter和setter方法
    ②Intent通过调用putExtra(String name, Serializable value)传入对象实例 当然对象有多个的话多个的话,我们也可以先Bundle.putSerializable(x,x);
    ③新Activity调用getSerializableExtra()方法获得对象实例: eg:Product pd = (Product) getIntent().getSerializableExtra("Product");
    ④调用对象get方法获得相应参数

    2.Parcelable实现:

    一般流程:

    ①业务Bean继承Parcelable接口,重写writeToParcel方法,将你的对象序列化为一个Parcel对象;
    ②重写describeContents方法,内容接口描述,默认返回0就可以
    ③实例化静态内部对象CREATOR实现接口Parcelable.Creator
    ④同样式通过Intent的putExtra()方法传入对象实例,当然多个对象的话,我们可以先 放到Bundle里Bundle.putParcelable(x,x),再Intent.putExtras()即可

    一些解释:

    通过writeToParcel将你的对象映射成Parcel对象,再通过createFromParcel将Parcel对象映射 成你的对象。也可以将Parcel看成是一个流,通过writeToParcel把对象写到流里面, 在通过createFromParcel从流里读取对象,只不过这个过程需要你来实现,因此写的 顺序和读的顺序必须一致。

    实现Parcelable接口的代码示例:

    //Internal Description Interface,You do not need to manage  
    @Override  
    public int describeContents() {  
         return 0;  
    }  
    @Override  
    public void writeToParcel(Parcel parcel, int flags){  
        parcel.writeString(bookName);  
        parcel.writeString(author);  
        parcel.writeInt(publishTime);  
    }  
    public static final Parcelable.Creator CREATOR = new Creator() {  
        @Override  
        public Book[] newArray(int size) {  
            return new Book[size];  
        }  
    @Override  
        public Book createFromParcel(Parcel source) {  
            Book mBook = new Book();    
            mBook.bookName = source.readString();   
            mBook.author = source.readString();    
            mBook.publishTime = source.readInt();   
            return mBook;  
        }  
    };

    Android Studio生成Parcleable插件:

    Intellij/Andriod Studio插件android-parcelable-intellij-plugin 只要ALT+Insert,即可直接生成Parcleable接口代码。

    另外:Android中大量用到Parcelable对象,实现Parcable接口又是非常繁琐的,可以用到 第三方的开源框架:Parceler,因为Ma ven的问题,暂时还没试。

    参考地址:[Android的Parcelable自动生成]

    3.两种序列化方式的比较:

    两者的比较:

    • 1)在使用内存的时候,Parcelable比Serializable性能高,所以推荐使用Parcelable。
    • 2)Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。
    • 3)Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的 持续性在外界有变化的情况下。尽管Serializable效率低点,但此时还是建议使用Serializable。

    5.Intent传递Bitmap

    bitmap默认实现Parcelable接口,直接传递即可

    实现代码:

    Bitmap bitmap = null;
    Intent intent = new Intent();
    Bundle bundle = new Bundle();
    bundle.putParcelable("bitmap", bitmap);
    intent.putExtra("bundle", bundle);

    6.传来传去不方便,直接定义全局数据

    如果是传递简单的数据,有这样的需求,Activity1 -> Activity2 -> Activity3 -> Activity4, 你想在Activity中传递某个数据到Activity4中,怎么破,一个个页面传么?

    显然不科学是吧,如果你想某个数据可以在任何地方都能获取到,你就可以考虑使用 Application全局对象了!

    Android 系统在启动每个应用进程时,都会创建一个 Application 对象,而且整个应用运行期间通常只会有这一个实例。所以,从这个角度看,Application 本身就具备单例(singleton)模式的特征。它的生命周期也是应用里最长的,基本上和整个程序的生命周期保持一致。正因为如此,如果有些数据不适合只用静态值来保存——无论是固定不变的,还是后续可能会变化的——就可以考虑放到 Application 里统一管理。不过要做到这一点,前提是先自定义一个类去继承 Application,并明确告诉系统:启动时要实例化的是这个自定义的 Application,而不是系统默认的那个。具体做法,就是在 AndroidManifest.xml 的 application 标签中添加 name属性!

    关键部分代码:

    1)自定义Application类:

    class MyApp extends Application {
        private String myState;
        public String getState(){
            return myState;
        }
        public void setState(String s){
            myState = s;
        }
    }

    2)AndroidManifest.xml中声明:

    3)在需要的地方调用:

    class Blah extends Activity {
        @Override
        public void onCreate(Bundle b){
            ...
        MyApp appState = ((MyApp)getApplicationContext());
        String state = appState.getState();
            ...
        }
    }

    高逼格写法

    :在任何位置都能获取到Application全局对象。

    Applicaiton是系统的一个组件,他也有自己的一个生命周期,我们可以在onCraete里获得这个 Application对象。贴下修改后的代码吧!

    class MyApp extends Application {
        private String myState;
        private static MyApp instance;
    public static MyApp getInstance(){
            return instance;
        }
    public String getState(){
            return myState;
        }
        public void setState(String s){
            myState = s;
        }
    @Override
        public void onCreate(){
            onCreate();
            instance = this;
        }
    }

    然后在任意地方我们就可以直接调用:MyApp.getInstance()来获得Application的全局对象!

    注意事项:

    Application对象是存在于内存中的,也就有它可能会被系统杀死,比如这样的场景:

    我们在Activity1中往application中存储了用户账号,然后在Activity2中获取到用户账号,并且显示!

    如果我们点击home键,然后过了N久候,系统为了回收内存kill掉了我们的app。这个时候,我们重新 打开这个app,这个时候很神奇的,回到了Activity2的页面,但是如果这个时候你再去获取Application 里的用户账号,程序就会报NullPointerException,然后crash掉~

    之所以会发生上述crash,是因为这个Application对象是全新创建的,可能你以为App是重新启动的, 其实并不是,仅仅是创建一个新的Application,然后启动上次用户离开时的Activity,从而创造App 并没有被杀死的假象!所以如果是比较重要的数据的话,建议你还是进行本地化,另外在使用数据的时候 要对变量的值进行非空检查!还有一点就是:不止是Application变量会这样,单例对象以及公共静态变量 也会这样~

    7.单例模式传参

    上面的Application就是基于单例的,单例模式的特点就是可以保证系统中一个类有且只有一个实例。 这样很容易就能实现,在A中设置参数,在B中直接访问了。这是几种方法中效率最高的。

    范例代码:(代码来自于网上~)

    ①定义一个单例类:

    public class XclSingleton  
    {  
        //单例模式实例  
        private static XclSingleton instance = null;  
    //synchronized 用于线程安全,防止多线程同时创建实例  
        public synchronized static XclSingleton getInstance(){  
            if(instance == null){  
                instance = new XclSingleton();  
            }     
            return instance;  
        }     
    final HashMap mMap;  
        private XclSingleton()  
        {  
            mMap = new HashMap();  
        }  
    public void put(String key,Object value){  
            mMap.put(key,value);  
        }  
    public Object get(String key)  
        {  
            return mMap.get(key);  
        }  
    } 

    ②设置参数:

    XclSingleton.getInstance().put("key1", "value1");  
    XclSingleton.getInstance().put("key2", "value2");  

    本节小结:

    好的,关于Intent复杂数据传输就到这里,本节除了讲述使用Intent来传递复杂数据外,还教了大家 使用Application和单例模式来传递参数!相信会对大家在数据传递方面带来方便,谢谢~

    本文内容来源于网友投稿,如有侵权请联系删除。
    作者最新文章
    系统应用
    相关文章 更多
    win10系统更新推送频繁怎么减少更新提示
    win10系统更新推送频繁怎么减少更新提示

    Windows 10更新弹窗频繁影响工作?无需禁用服务,只需调整活动时间、安排重启和优化通知设置,即可有效减少干扰并保持系统安全。

    win10怎么查看当前系统自动更新有没有被关闭
    win10怎么查看当前系统自动更新有没有被关闭

    想知道Win10自动更新是否被关闭?不要只看任务栏。本文教你通过“设置-更新和安全”、“高级选项”及“services.msc服务”三处位置,准确判断系统更新状态是暂停、运行还是受组织策略管理。

    win10休眠唤醒和开机登录密码可以分开取消吗?
    win10休眠唤醒和开机登录密码可以分开取消吗?

    想知道Win10能否只取消休眠唤醒密码而保留开机密码?本教程详解如何通过系统设置和netplwiz工具,分别控制开机登录与睡眠唤醒后的验证要求,实现灵活的安全策略。

    win10取消开机密码之后如何恢复密码登录
    win10取消开机密码之后如何恢复密码登录

    Win10取消开机密码后想恢复?本教程详解如何通过netplwiz恢复开机输入框、重新设置空密码账户、配置PIN码及调整睡眠唤醒登录策略,步骤清晰,即改即验。

    win10注册表修改怎么取消开机自动登录密码
    win10注册表修改怎么取消开机自动登录密码

    想恢复Win10开机密码保护?本文详解如何通过注册表修改AutoAdminLogon值取消自动登录,配合netplwiz工具复核,避免凭据泄露风险,适合家用及办公场景参考。

    win10电脑一开机就下载更新怎么关闭
    win10电脑一开机就下载更新怎么关闭

    Win10一开机就占用网速下载更新?本文教你通过设置暂停更新、调整活动时间及标记计费网络来缓解干扰。区分家庭版与专业版操作差异,避免强制停止服务带来的系统风险,让更新在合适的时间进行。

    win10取消开机密码时输入密码验证失败怎么解决
    win10取消开机密码时输入密码验证失败怎么解决

    Win10取消开机密码时提示验证失败?可能是因为输错了Microsoft账户密码或误用了PIN码。本文详解如何确认账户类型、正确输入凭据及检查自动登录设置,帮你解决验证报错问题。

    win10忘记当前密码了怎么处理完整方法
    win10忘记当前密码了怎么处理完整方法

    Windows 10忘记开机密码如何处理?本文根据账户类型(Microsoft账户/本地账户/PIN)提供官方支持的恢复步骤,包括在线重置、安全问题回答及管理员重置方法,避免数据丢失风险。

    win10更新提示不断弹出如何永久关闭通知
    win10更新提示不断弹出如何永久关闭通知

    Windows 10更新提示频繁弹窗怎么办?本文详解如何通过Windows更新高级选项、系统通知设置及暂停更新功能,精准关闭不必要的重启提醒和横幅通知,同时确保系统安全更新不受影响。适用于家庭及个人用户,区分个人设置与企业策略管理。

    win10家庭版能不能取消开机密码,操作步骤是什么
    win10家庭版能不能取消开机密码,操作步骤是什么

    Win10家庭版如何取消开机密码?本文详解本地账户清空密码步骤及Microsoft账户自动登录设置方法,分析安全风险与例外情况,帮助用户在便捷与安全间做出合理选择。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    macOS软件
    macOS软件

    正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

    Mac软件 更多
    photoshop
    photoshop
    Windows、macOS 、 iPad

    Photoshop 2026 是 Adobe 推出的专业图像处理与视觉设计软件,支持 Windows、macOS 和 iPad 等平台,广泛应用于摄影修图、电商设计、平面海报、数字绘画及视觉合成等创作场景。

    Blender
    Blender
    Windows、macOS 和 Linux

    Blender 是一款免费开源、跨平台的专业 3D 创作软件,集建模、动画、渲染、视频编辑与视觉合成等功能于一体,广泛应用于影视动画、游戏设计和建筑可视化等领域。软件支持 Cycles 物理渲染器与 Eevee 实时渲染引擎,并提供多边形建模、骨骼绑定、物理模拟等专业工具。Blender 兼容 Windows、macOS 和 Linux 系统,安装包轻巧、运行流畅,依托活跃的全球开发者社区持续更新,是从初学者到专业创作者都值得选择的正版 3D 创作工具。

    灵活计算器
    灵活计算器
    macOS/iOS/Android

    灵活计算器是一款笔记式算数应用,支持实时计算、动态关联和云端同步功能。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

    WINDOWS 更多
    3dmax(3ds max)
    3dmax(3ds max)
    Windows

    Autodesk 3ds Max 是一款专业的三维建模、动画与渲染软件,广泛应用于建筑可视化、游戏开发、影视动画、广告设计和产品展示等领域。

    photoshop
    photoshop
    Windows、macOS 、 iPad

    Photoshop 2026 是 Adobe 推出的专业图像处理与视觉设计软件,支持 Windows、macOS 和 iPad 等平台,广泛应用于摄影修图、电商设计、平面海报、数字绘画及视觉合成等创作场景。

    Blender
    Blender
    Windows、macOS 和 Linux

    Blender 是一款免费开源、跨平台的专业 3D 创作软件,集建模、动画、渲染、视频编辑与视觉合成等功能于一体,广泛应用于影视动画、游戏设计和建筑可视化等领域。软件支持 Cycles 物理渲染器与 Eevee 实时渲染引擎,并提供多边形建模、骨骼绑定、物理模拟等专业工具。Blender 兼容 Windows、macOS 和 Linux 系统,安装包轻巧、运行流畅,依托活跃的全球开发者社区持续更新,是从初学者到专业创作者都值得选择的正版 3D 创作工具。

    网站备案号:苏ICP备2026018738号-1 联系邮箱:bd@zhengruan.com 网站地图

    Copyright ©2018-2026