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
仍旧拿前面的两个 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 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 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 执行完。
因 And
roid framework 已经做好所有的事情,所以当我们不需要关注提交操作的返回值时,可以将 commit 无条件替换 apply 使用,而且 AS 也会建议将 commit 替换成 apply。
**3、**SharedPreferences 支持的数据类型都必须是支持序列化操作的,上面提到的 Set是一个 interface,我们并不能直接实例化,但我们可以使用它的直接或间接实现类,比如:HashSet、TreeSet、LinkedHashSet等等。
我们查看这几个的实现,不难发现,它们也都是实现了 Serializable 接口,支持序列化操作的:
public class HashSet
extends AbstractSet
implements Set, Cloneable, java.io.Serializable
public class TreeSet extends AbstractSet
implements NavigableSet, Cloneable, java.io.Serializable
public class LinkedHashSet
extends HashSet
implements Set, 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=“