一些闲聊
距离上一篇文章似乎又是很久了,看起来也没有很多反馈,催更就更不用说了。哈哈,放弃了。
话说最近公司在招聘一批至少 5 年开发经验的 Android 开发工程师,我也是忙开了花,激动得不行呀。虽说我面试过的技术开发至少 50 人以上,但这还是第一次开始面试 Android,此时犹如大姑娘上轿,还真是头一回呀!
所以非常非常非常用心地准备了良久,然后满怀激动地开始了我的 Android 面试官角色。
无奈,面试后的感觉,均是开发效率听起来很牛逼,第三方 API 用起来非常顺手,但问到基础,就拿我面试系列的题去问,没一个答得上的,甚至是循循善诱,都没法好好回答。
面试场景
Android 开发中对两个 Activity 之前传递数据,应该很熟悉吧?
嗯,当然没问题。一般采用 Intent.putXXX()
就可以实现各种轻量级数据的传递。
那对于自定义的 Object 呢?
直接使用 Bundle
的 putSerializable()
即可。需要把对象实现 Serializable
接口,最后使用 Intent.putExtras(Bundle)
把数据放进 Intent
即可。
除了这种方式,还有其它方式吗?和这种方式有什么区别呢?
我知道还有 Bundle.putParcelable()
,不过我们平时基本都只用 Serializable
方式。
为什么不用
Parcelable
方式呢?它们有什么不同呢?
因为简单呀,Serializable
方式只需要实现接口一句代码就好了,Parcelable
我记得有很多代码。对于它们的区别嘛,em......额......嗯.......
正文
上面的场景,实际上就是在我近期发生的。作为一个简历上 09 年入行的大龄 Android 程序员,我非常肯定他的开发能力和解决问题的能力,在这方面肯定甩我很多条街,不过至少在我问的问题上让我有点大跌眼镜,问到自定义 View 的绘制顺序,直接回答不知道。问到 LauchMode,支支吾吾,不清楚。实际上不由得让我们思考,到底是怎么了,难道现在对于这么多的程序猿,写出符合需求的代码就变得这么重要了么?还好,当下还有很多坚持在一线,努力把基础带给大家的大神,比如,扔物线朱凯,还有非常非常多的伙伴们。
大多数人可能都知道,Serializable
和 Parcelable
方式最大的区别是效率上的差异,而且对于小数据,其实差异并不是很大,这些差别其实用户层面是并不容易发现的。但这并不代表着,我们的开发就可以忽视这几十毫秒甚至是几毫秒的差距。
Serializable 和 Parcelable 的区别
可以肯定的是,两者都是支持序列化和反序列化的操作。
两者最大的区别在于 存储媒介的不同,Serializable
使用 I/O 读写存储在硬盘上,而 Parcelable
是直接 在内存中读写。很明显,内存的读写速度通常大于 IO 读写,所以在 Android 中传递数据优先选择 Parcelable
。
Serializable
会使用反射,序列化和反序列化过程需要大量 I/O 操作, Parcelable
自已实现封送和解封(marshalled &unmarshalled)操作不需要用反射,数据也存放在 Native 内存中,效率要快很多。
有人直接比较过两个的效率差别
我们可以来看看分别怎么写?
- Serializable 「简单易用」一直都是它的代名词
public class TestSerializable implements Serializable {
String msg;
List<ItemBean> datas;
public static class ItemBean implements Serializable{
String name;
}
}
- Parcelable 速度至上
public class TestParcelable implements Parcelable {
String msg;
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.msg);
}
TestParcelable(String msg) {
this.msg = msg;
}
private TestParcelable(Parcel in) {
this.msg = in.readString();
}
public static final Creator<TestParcelable> CREATOR = new Creator<TestParcelable>() {
@Override
public TestParcelable createFromParcel(Parcel source) {
return new TestParcelable(source);
}
@Override
public TestParcelable[] newArray(int size) {
return new TestParcelable[size];
}
};
}
很明显,Parcelable
实现起来并不容易,它有成吨的模板代码,这使得对象变得难以阅读和维护。但如果你真的想成为一个优秀的 Android 开发工程师,你可能就得多在 Parcelable
上花点时间了。实在想偷懒也没事,因为有人在 GitHub 上已经上传了 Android Studio 的插件,帮助你自动生成这一堆模板。
地址:https://github.com/mcharmas/android-parcelable-intellij-plugin
在两个 Activity 之间传递对象还需要注意什么呢?
对象的大小,对象的大小,对象的大小!!!
重要的事情说三遍,一定要注意对象的大小。Intent
中的 Bundle
是使用 Binder
机制进行数据传送的。能使用的 Binder 的缓冲区是有大小限制的(有些手机是 2 M),而一个进程默认有 16 个 Binder
线程,所以一个线程能占用的缓冲区就更小了( 有人以前做过测试,大约一个线程可以占用 128 KB)。所以当你看到 The Binder transaction failed because it was too large
这类 TransactionTooLargeException
异常时,你应该知道怎么解决了。