在Activity间传递的数据一般比较简单,但是有时候实际开发中也会传一些比较复杂的数据,本节一起来学习更多Activity间数据的传递方法。

1、通过 Intent 传递

我们在进行 Activity 跳转时,是要有 Intent,此时 Intent 是可以携带数据的,我们可以利用它将数据传递给其它Activity。Intent 应该是系统提供的支持类型最广,功能最全面的传递方式了。基本数据类型、复杂数据类型(如数组、集合)、自定义数据类型等等都能支持,而且使用起来也不复杂。下面将通过几个小栗子分别介绍一下这几种方法。

1.1、基本数据类型传递

String 不是基本数据类型,Java 的基本数据类型有且仅有8种,Intent 都做了很好的支持。这8种基本类型都有自己的包装类型(Wrap Class,复杂类型),而且包装类型也实现了 Serializable 接口(后面再说),使得 Intent 也能很好的支持包装类型。

8种基本类型及其包装类对应关系如下:

容我煮个栗子:

假设有 Activity1,Activity2 两个 Activity;如果要在 Activity1 中启动 Activity2,并传过去几个基本类型的数据,就可以这么写:

Intent intent = new Intent(this, Activity2.class);
intent.putExtra(String name, boolean value);
intent.putExtra(String name, byte value);
intent.putExtra(String name, char value);
intent.putExtra(String name, short value);
intent.putExtra(String name, int value);
intent.putExtra(String name, float value);
intent.putExtra(String name, long value);
intent.putExtra(String name, double value);
startActivity(intent);

在 Activity2 的 onCreate 中就可以通过如下方式接收:

Intent intent = getIntent();
boolean bool = intent.getBooleanExtra(String name, boolean defaultValue);
byte bt = intent.getByteExtra(String name, byte defaultValue);
char ch = intent.getCharExtra(String name, char defaultValue);
short sh = intent.getShortExtra(String name, short defaultValue);
int i = intent.getIntExtra(String name, int defaultValue);
float fl = intent.getFloatExtra(String name, float defaultValue);
long lg = intent.getLongExtra(String name, long defaultValue);
double db = intent.getDoubleExtra(String name, double defaultValue);

PS:上面发送和接收的时候,同一个字段必须使用相同的 name,比如:intent.putExtra(“BOOLEAN”, true);intent.getBooleanExtra(“BOOLEAN”, false);

1.2、复杂数据类型传递

Java 中也定义了一些常用的复杂类型,比如 String、基本数据类型的数组、ArrayList、HashMap 等等,Intent 也对它们做了支持,使得我们能很容易的通过 Intent 传递这些复杂类型。方法与上面基本类型类似,比如:

intent.putExtra(String name, String value);
intent.putExtra(String name, int[] value);
intent.putExtra(String name, Parcelable value);
intent.putExtra(String name, Serializable value);
intent.putExtra(String name, CharSequence value);
intent.putStringArrayListExtra(String name, ArrayList<String> value);

接收方式也类似,这里就不再一一列举了。

不过,像 ArrayList、HashMap 这种,本身还能存放复杂类型的数据结构,要想通过 Intent 传递,得确保它们内部存放的类型也是能支持序列化和反序列化的。

1.3、自定义数据类型传递

上面已经列举了很多 Intent 支持的类型,但是默认提供的这些类型,总归是不够用的,很多时候我们会定义自己的数据类型,比如定义一个 Student:

public class Student{public String name;public int age;
}

那么这个时候我们应该如何通过Intent来传递呢?

1.3.1、实现 Serializable 接口

我们先看一下默认提供并被 Intent 支持的复杂数据类型的实现方式:

public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence
public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable
public class HashMap<K,V>extends AbstractMap<K,V>implements Map<K,V>, Cloneable, Serializable

我们可以看到它们有一个共同的特点,都 implement 了 Serializable 接口。

Serializable 是一个空接口,它没有定义任何方法,知识用来标记其实现类是支持序列化和反序列化的。

因此当我们想让自定义的类型也能通过 Intent 传递时,只需要让该类实现 Serializable 接口即可。

依旧用 Student 来煮个栗子:

public class Student implements Serializable{private static final long serialVersionUID = 1L;public String name;public int age;
}

传递方法就是:

intent.putExtra(String name, Serializable value);
intent.getSerializableExtra(String name);

PS:关于 Serializable 还有一些知识点,比如:serialVersionUID、静态变量序列化、transient 关键字、继承问题等等,这里就不介绍了,有兴趣的可以自行去查阅。

1.3.2、实现 Parcelable 接口

上面介绍了 Serializable 接口,但 Serializable 是 Java 的实现,Android 下能正常使用,没毛病,但 Google 觉得 Serializable 在 Android 内存不大性能不强的情况下的效率不太够,于是为 Android 量身定制了一个专用的接口——Parcelable。

还是用 Student 来煮栗子:

要想实现 Parcelable 接口,只需要先写好 Student 类和属性,然后让 Student 实现Parcelable,再然后根据 AS 的两步提示:第一步重写 describeContents 和 writeToParcel,第二步创建 CREATOR 就大功告成了。写好的类如下:

public class Student implements Parcelable{public String name;public int age;protected Student(Parcel in) {name = in.readString();age = in.readInt();}public static final Creator<Student> CREATOR = new Creator<Student>() {@Overridepublic Student createFromParcel(Parcel in) {return new Student(in);}@Overridepublic Student[] newArray(int size) {return new Student[size];}};@Overridepublic int describeContents() {return 0;}@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeString(name);dest.writeInt(age);}
}

此时通过 Intent 去传递就可以使用如下方法:

intent.putExtra(String name, Parcelable value);
intent.getParcelableExtra(String name);

这两种实现序列化的方法的使用原则:

1)在使用内存的时候,Parcelable 比 Serializable 性能高,所以推荐使用 Parcelable。

2)Serializable 在序列化的时候会产生大量的临时变量,从而引起频繁的 GC。

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

PS:Intent 还支持通过 Bundle 封装数据,然后传递 Bundle,但是查看 intent.putExtra 的实现,我们会发现,其实 intent.putExtra 的内部也是维护的一个 Bundle,因此,通过 putExtra 放入的数据,取出时也可以通过 Bundle 去取。

2、通过全局变量传递

顾名思义,就是借助一个全局变量做中转,去传递数据。还是以前面的两个 Activity 为例,传递不支持序列化的 Student 对象。我们可以先创建一个工具类,比如:

public class Transmitter {public static Student student;
}

那么传递和接收时,就可以这么操作:

//传递
Student stu = new Student();
Transmitter.student = stu;
Intent intent = new Intent(this, Activity2);
startActivity(intent);
//接收
onCreate(...){Student stu = Transmitter.student;
}

可以看到使用起来非常的方便快捷。

但是,全局变量在 APP 运行期间一直存在,如果通过全局变量存放的数据量比较大,变量个数多;并且在不需要使用后,没有及时的将全局变量置为 null,好让 GC 去回收,那么是有可能会引发 OOM 问题的。

因此,如果要使用全局变量来作为数据传递方法,那么就一定要注意维护好这些全局变量的状态。

3、通过 SharedPreferences 传递

SharedPreferences 是 Android 提供的一种实现数据存储的方式,它可以将数据以 xml 格式存储在机器中,通常用来存储 APP 的设置信息,我们也可以用它来实现 Activity 间的数据传递。

但是,SharedPreferences 因其特殊的工作方式,只提供了对部分基本类型和 String 的操作,对其它既有复杂类型和自定义类型是不支持的。它所支持的类型只有:

boolean
float
int
long
String
Set<String>

仍旧拿前面的两个 Activity 煮栗子,要实现它们之间的数据传递,只需要现在 Activity1 中,将数据放入 SharedPreferences,如下:

SharedPreferences sp = getSharedPreferences("FILENAME", MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putBoolean(String key, boolean value);
editor.putFloat(String key, float value);
editor.putInt(String key, int value);
editor.putLong(String key, long value);
editor.putString(String key, String value);
editor.putStringSet(String key, Set<String> values);
//editor.commit();
editor.apply();
startActivity(...);

然后在 Activity2 中通过 SharedPreferences 将数据取出来,如下:

SharedPreferences sp = getSharedPreferences("FILENAME", MODE_PRIVATE);
sp.getBoolean(String key, boolean defValue);
sp.getFloat(String key, float defValue);
sp.getInt(String key, int defValue);
sp.getLong(String key, long defValue);
sp.getString(String key, String defValue);
sp.getStringSet(String key, Set<String> defValue);

关于 SharedPreferences 有几点需要注意:

**1、**getSharedPreferences(“FILENAME”, MODE_PRIVATE) 是通过 Context 调用的,发送和接收的 FILENAME、MODE_PRIVATE 都要一致。

2、发送时,往 SharedPreferences 存入数据后,需要提交,提交的方式有两种:commit、apply,这两个的区别如下:

**commit:**同步操作,立即将修改写到 Storage,有 boolean 类型返回值。

**apply:**立即刷新 In-memory 中的数据,然后启动异步任务将修改写到 Storage,无返回值。

当两个 apply 同时操作时,后调用 apply 的将会被保存到 Storage 中;当有 apply正在执行时,调用 commit,commit 将被阻塞,直到 apply 执行完。

因 Android framework 已经做好所有的事情,所以当我们不需要关注提交操作的返回值时,可以将 commit 无条件替换 apply 使用,而且 AS 也会建议将 commit 替换成 apply。

**3、**SharedPreferences 支持的数据类型都必须是支持序列化操作的,上面提到的 Set是一个 interface,我们并不能直接实例化,但我们可以使用它的直接或间接实现类,比如:HashSet、TreeSet、LinkedHashSet等等。

我们查看这几个的实现,不难发现,它们也都是实现了 Serializable 接口,支持序列化操作的:

public class HashSet<E>extends AbstractSet<E>implements Set<E>, Cloneable, java.io.Serializable
public class TreeSet<E> extends AbstractSet<E>implements NavigableSet<E>, Cloneable, java.io.Serializable
public class LinkedHashSet<E>extends HashSet<E>implements Set<E>, Cloneable, java.io.Serializable {

4、通过 SystemProperties 传递

这个类可以看做一个维护全局变量的类,只不过这里的全局变量是系统的,它们的值是 build.prop 文件里面的内容。我们先看一下它的定义:

/*** Gives access to the system properties store. The system properties* store contains a list of string key-value pairs.** {@hide}*/
public class SystemProperties

没错,这玩意是个 hide 的类,那就意味着正常情况下 SDK 里面是没有的,AS 里面也是访问不到的。不过我们还是可以通过一些手段去访问到它,比如反射、将源码的库导出到 AS 使用、将 APP 放在源码中编译等等。

这里我们就不关注用什么手段去访问它了,我们重点还是在利用它进行 Activity 之间的数据传递。

假设我们是在源码中编译,还是用一开始的两个 Activity 来煮栗子,发送数据时可以这么操作:

SystemProperties.set("NAME", "Shawn.XiaFei");
startActivity(...);

接收时就可以这么写:

SystemProperties.get("NAME");
//或者
SystemProperties.get("NAME", "defValue");

是不是很方便呢,不过别激动,我们看下 set 的实现:

/*** Set the value for the given key.* @throws IllegalArgumentException if the key exceeds 32 characters* @throws IllegalArgumentException if the value exceeds 92 characters*/
public static void set(String key, String val) {if (key.length() > PROP_NAME_MAX) {throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);}if (val != null && val.length() > PROP_VALUE_MAX) {throw new IllegalArgumentException("val.length > " +PROP_VALUE_MAX);}native_set(key, val);
}

看注释,没错,key 和 val 都限制了长度的!!!当然,32和92字符,在一般情况下也还是够用的。但是下面就要说一般 APP 开发可能无法完成的事了。

前面说了,这玩意是 SDK 不可见的,而且它维护的是系统的属性值,系统属性值 APP 可以读,但不能轻易修改。因此上面 set 的时候,如果权限不够就会报如下错误:

Unable to set property "NAME" to "Shawn.XiaFei": connection failed; errno=13 (Permission denied)
type=1400 audit(0.0:167): avc: denied { write } for name="property_service" dev="tmpfs" ino=10696 scontext=u:r:untrusted_app_25:s0:c512,c768 tcontext=u:object_r:property_socket:s0 tclass=sock_file permissive=0

这个错误在 Rom 开发中比较常见,解决办法就是配置相应的 avc 权限,这一操作是一般 APP 开发者无法进行的。有兴趣的可以自己去查资料,这里不做介绍。

5、通过 SettingsProvider 传递

爱折腾的人可能注意到了 Android 设备上一般都会有这么一个应用,它的作用是通过数据库去维护一些系统配置信息。在 Rom 开发中,通常借助它设置首次开机的默认行为。

通过它传递数据的关键在 android.provider.Settings 类,这个类里面有 3 个常用的静态内部类,分别是:Global、System、Secure,它们分别对应不同的权限等级。

煮栗子了:

发送时,这么写就可以了:

/*Settings.System.putInt(ContentResolver cr, String name, int value);
Settings.System.putString(ContentResolver cr, String name, String value);
Settings.System.putFloat(ContentResolver cr, String name, float value);
Settings.System.putLong(ContentResolver cr, String name, long value);*/
Settings.Global.putString(getContentResolver(), "NAME", "Shawn.XiaFei");
startActivity(...);

接收时,就这么写:

String name = Settings.Global.getString(getContentResolver(), "NAME");

使用起来也是很简单滴!不过,使用起来虽然简单,但也并不是那么容易的。它也是要权限的!!!

如果权限不够,运行的时候就会报如下错误:

 java.lang.RuntimeException: Unable to start activity ComponentInfo{xxx.xxx/xxx.xxx.Activity1}: java.lang.SecurityException: Permission denial: writing to settings requires:android.permission.WRITE_SECURE_SETTINGSat android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2805)at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2883)at android.app.ActivityThread.-wrap11(Unknown Source:0)at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1613)at android.os.Handler.dispatchMessage(Handler.java:106)at android.os.Looper.loop(Looper.java:164)at android.app.ActivityThread.main(ActivityThread.java:6523)at java.lang.reflect.Method.invoke(Native Method)at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:857)

意思很明了,得给它 WRITE_SECURE_SETTINGS 的权限,我们试着在 Manifest 里面添加一下,结果 AS 标红了,提示如下:

Permissions with the protection level signature or signatureOrSystem are only granted to system apps. If an app is a regular non-system app, it will never be able to use these permissions.

意思就是说,这个权限只有系统 APP 才能获得,三方 APP 没戏。

6、通过数据库传递

其实上面介绍的 SettingsProvider 方法,也是通过数据库实现的,只不过它对数据库的操作做了封装,我们感觉不到而已。既然如此,我们也可以在自己 APP 中创建数据库,然后通过数据库来实现 Activity 之间的数据传递。

栗子煮太多,吃不动,不煮了,有兴趣的可以自己去查一下数据库的知识。

PS:实话实说吧,个人用的不多,忘了怎么玩了……

7、通过文件传递

前面提到的 SharedPreferences 也是基于文件实现的,只不过 SharedPreferences 是固定成 xml 格式的文件。我们也可以通过自定义文件操作方式去实现数据的存取,进而实现 Activity 之间的数据传递。

说了栗子不煮了,有兴趣自己去查一下吧。

PS:原因同上一条……

总结

其实 Activity 之间数据传递的方法还是很多的,也各有优缺点,但最最最最最常用的还是第一种—— Intent,其他方法都是理论可行,实际使用起来都会有点鸡肋,或者得不偿失。

因此要想掌握好 Activity 之间数据传递的技巧,个人觉得只需要掌握 Intent 的用法,能熟练使用,灵活处理就 OK 了。至于其它方法,能说得出来原理就可以了。

最后

针对Android程序员,我这边给大家整理了一些资料,包括不限于高级UI、性能优化、移动架构师、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!

  • Android前沿技术大纲

  • 全套体系化高级架构视频

资料领取方式: 加群免费获取 Android架构设计大群(185873940)

最后送福利了,现在关注我并且加入群聊可以获取包含源码解析,自定义View,动画实现,架构分享等。
内容难度适中,篇幅精炼,每天只需花上十几分钟阅读即可。
大家可以跟我一起探讨,欢迎加群探讨,有flutter—底层开发—性能优化—移动架构—资深UI工程师 —NDK相关专业人员和视频教学资料,还有更多面试题等你来拿

点击GitHub领取

自定义View,动画实现,架构分享等。
内容难度适中,篇幅精炼,每天只需花上十几分钟阅读即可。
大家可以跟我一起探讨,欢迎加群探讨,有flutter—底层开发—性能优化—移动架构—资深UI工程师 —NDK相关专业人员和视频教学资料,还有更多面试题等你来拿**
点击GitHub领取
[外链图片转存中…(img-1ZVXg49m-1623503402786)]

【好文推荐】Activity之间的数据传递方法汇总相关推荐

  1. Activity之间的数据传递方法汇总系列教学

    近日一好友去阿里面试,面试失败了,分享了一个他最不擅长的算法面试题.题目是这样的. 题目:给定一个二叉搜索树(BST),找到树中第 K 小的节点. 出题人:阿里巴巴出题专家:文景/阿里云 CDN 资深 ...

  2. Android中Activity之间的数据传递(Intent和Bundle)

    当一个Activity启动另一个Activity时,常常会有一些数据传过去,对于Activity之间的数据交换更简单,因为两个Activity之间进行数据传递交换更简单,因为两个Activity之间本 ...

  3. Android--Activity的跳转及Activity之间的数据传递

    Activity的跳转及Activity之间的数据传递(作业) 首先呢,看到这个作业第一感觉并不难,因为只是涉及到多activity之间的跳转以及简单的数据传递而已.然后,做的时候也没花费多长的时间, ...

  4. Android零基础入门第83节:Activity间数据传递方法汇总

    2019独角兽企业重金招聘Python工程师标准>>> 在Activity间传递的数据一般比较简单,但是有时候实际开发中也会传一些比较复杂的数据,本节一起来学习更多Activity间 ...

  5. Activity的创建步骤+Activity之间的数据传递+案例(人品测试器)

    Android的四大组件: 1.activity(多层界面运用) 2.广播接收者 3.服务 4.内容提供者 此外,我这里还会说道 5.多媒体编程(图形.声音.视频) 6.Fragment+动画 7.S ...

  6. 【无标题】Android在activity之间发送数据(putExtra方法)

    Activity 之间发送数据(putExtra方法详解) 当应用创建 Intent 对象以在 startActivity(android.content.Intent) 中用于启动新的 Activi ...

  7. android activity之间传递对象,Android Activity之间的数据传递

    一.通过startActivity来进行Activity的传值 在Android中,如果我们要通过一个Activity来启动另一个Activity,可以使用 startActivity(Intent ...

  8. Activity之间的数据传递—实现Parcelable接口

    一.单向传递数据和接收 1.可以传递数据类型 传递基本数据类型.字符串和对应的数组 传递Bundle(类似HashMap) 传递对象数据 传递Integer集合.String集合和parcelable ...

  9. 常见的Android数据传递方法汇总

    一.Intent与Bundle 1.Activty与Activity 1.1.传递简单数据 (1) 传单个值(以String类型为例) 发送数据 Intent intent = new Intent( ...

最新文章

  1. 40 万年薪招应届生?OPPO 狂揽芯片人才,应届生招聘行情究竟如何?
  2. git 上传代码到指定仓库_初次使用git上传代码到github远程仓库
  3. 大约xib连接错误bug正确
  4. OpenGL在frag着色器中模拟手电筒效果
  5. android 微信缩小通话界面_安卓如何做出微信那样的界面仿微信“我”的界面2/5...
  6. 通过VisualSVN的POST-COMMIT钩子自动部署代码
  7. CDateTimeUI类源码分析
  8. dj电商-模型类设计-1.x-模型类抽象基类
  9. 最流畅的手机,性能、跑分却弱爆了?2019年上半年手机数据报告出炉
  10. 95-290-050-源码-内存管理-堆外内存与堆内内存概述
  11. oracle字段id加1,oracle 字段ID自动增1
  12. 空降到一个公司做高管,怎么打开局面?
  13. python星星闪烁_python实现while循环打印星星的四种形状
  14. html sql 编辑器,【web】CodeMirror打造SQL在线编辑器
  15. Date DateFormat SimpleDateFormat Calendar Joda-Time
  16. hdu 5755 Gambler Bo【gauss】
  17. 数据结构——前序线索二叉树及其前序遍历
  18. Sharepoint visio Web Access
  19. 【IoT】产品管理:产品部管理管理规章与制度
  20. 机器视觉、halcon visionpro 的使用感受

热门文章

  1. linux根文件系统配置,Linux学习笔记__ Linux根文件系统详解
  2. miRNA的特征、功能及识别方法等详解
  3. 人脸识别系统的实现与封装
  4. 数据结构——栈,队列,及其结构特点应用。
  5. 华清远见嵌入式培训_第一周回顾与反思
  6. 1--if中的return的作用/条件判断中如何退出函数
  7. 水晶报表填充.Net Objects数据源
  8. 【算法】一文详解贪心法
  9. discuz 版块导航function_forumlist.php,Discuz! X2扩建左侧版块导航 社区层次一目了然...
  10. k-means聚类算法——c语言