Android面试题(25)-Bundle机制
Bundle的概念理解
Bundle对于Android开发者来说肯定非常眼熟,它经常出现在以下场合:
- Activity状态数据的保存与恢复涉及到的两个回调:
void onSaveInstanceState (Bundle outState)
、void onCreate (Bundle savedInstanceState)
- Fragment的setArguments方法:
void setArguments (Bundle args)
- 消息机制中的Message的setData方法:
void setData (Bundle data)
- 其他场景不再列举
Bundle从字面上解释为“一捆、一批、一包”,结合上述几个应用场合,可以知道Bundle是用来传递数据的,我们暂将Bundle理解为Android中用来传递数据的一个容器。官方文档对Bundle的说明如下:
Bundle实现了Parcelable接口,所以他可以方便的在不同进程间传输,这里要注意我们传输的数据必须能够被序列化;
Bundle源码分析
首先看它的声明
public final class Bundle extends BaseBundle implements Cloneable, Parcelable
第一,它使用final修饰,所以不可以被继承
第二,它实现了两个接口,cloneable和Parcelable,这就意味着他必须实现以下方法:
public Object clone()
public int describeContents()
public void writeToParcel(Parcel parcel, int flags)
public void readFromParcel(Parcel parcel)
public static final Parcelable.Creator<Bundle> CREATOR = new Parcelable.Creator<Bundle>()
再看他的内存结构:
ArrayMap<String, Object> mMap = null;
使用的是ArrayMap,这个集合类存储的也是键值对,但是与Hashmap不同的是,hashmap采用的是“数组+链表”的方式存储,而Arraymap中使用的是两个数组进行存储,一个数组存储key,一个数组存储value,内部的增删改查都将会使用二分查找来进行,这个和SparseArray差不多,只不过sparseArray的key值只能是int型的,而Arraymap可以是map型,所以在数据量不大的情况下可以使用这两个集合代替hashmap去优化性能;
我们知道Bundle其实就是一个容器,内部使用了Arraymap去存储数据,那么就必然会提供get,put方法,由于Bundle支持的数据类型太多,这里我们就看一个布尔类型的,其他类型的方式都差不多;
getBoolean
public boolean getBoolean(String key, boolean defaultValue) {unparcel(); Object o = mMap.get(key); if (o == null) {return defaultValue; }try {return (Boolean) o; } catch (ClassCastException e) {typeWarning(key, o, "Boolean", defaultValue, e); return defaultValue; } }
数据读取的逻辑很简单,就是通过key从ArrayMap里读出保存的数据,并转换成对应的类型返回,当没找到数据或发生类型转换异常时返回缺省值。
putBoolean
public void putBoolean(@Nullable String key, boolean value) {unparcel(); mMap.put(key, value); }
这里出现了一个unparcel()方法
/* package */ void unparcel() {synchronized (this) {final Parcel parcelledData = mParcelledData; if (parcelledData == null) {if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))+ ": no parcelled data"); return; }if (LOG_DEFUSABLE && sShouldDefuse && (mFlags & FLAG_DEFUSABLE) == 0) {Slog.wtf(TAG, "Attempting to unparcel a Bundle while in transit; this may " + "clobber all data inside!", new Throwable()); }if (isEmptyParcel()) {if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this)) + ": empty"); if (mMap == null) {mMap = new ArrayMap<>(1); } else {mMap.erase(); }mParcelledData = null; return; }int N = parcelledData.readInt(); if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))+ ": reading " + N + " maps"); if (N < 0) {return; }ArrayMap<String, Object> map = mMap; if (map == null) {map = new ArrayMap<>(N); } else {map.erase(); map.ensureCapacity(N); }try {parcelledData.readArrayMapInternal(map, N, mClassLoader); } catch (BadParcelableException e) {if (sShouldDefuse) {Log.w(TAG, "Failed to parse Bundle, but defusing quietly", e); map.erase(); } else {throw e; }} finally {mMap = map; parcelledData.recycle(); mParcelledData = null; }if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))+ " final map: " + mMap); } }
先来看下BaseBundle中mParcelledData的定义:
Parcel mParcelledData = null;
在大部分情况下mParcelledData都是null,因此unparcel()直接返回。当使用构造函数public Bundle(Bundle b)
创建Bundle时,会给mParcelledData赋值;
void copyInternal(BaseBundle from, boolean deep) {synchronized (from) {if (from.mParcelledData != null) {if (from.isEmptyParcel()) {mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL; } else {mParcelledData = Parcel.obtain(); mParcelledData.appendFrom(from.mParcelledData, 0, from.mParcelledData.dataSize()); mParcelledData.setDataPosition(0); }} else {mParcelledData = null; }if (from.mMap != null) {if (!deep) {mMap = new ArrayMap<>(from.mMap); } else {final ArrayMap<String, Object> fromMap = from.mMap; final int N = fromMap.size(); mMap = new ArrayMap<>(N); for (int i = 0; i < N; i++) {mMap.append(fromMap.keyAt(i), deepCopyValue(fromMap.valueAt(i))); }}} else {mMap = null; }mClassLoader = from.mClassLoader; } }
从上述代码片段可以知道mParcelledData的取值有3种情况:
- mParcelledData = EMPTY_PARCEL
- mParcelledData = Parcel.obtain()
- mParcelledData = null
在unparcel()
方法中就对上述几种情况做了不同的处理,当mParcelledData为null时,直接返回;当mParcelledData为EMPTY_PARCEL时,会创建一个容量为1的ArrayMap对象;当mParcelledData为Parcel.obtain()时,则会将里面的数据读出,并创建一个ArrayMap,并将数据存储到ArrayMap对象里面,同时将mParcelledData回收并置为null;
Android面试题(25)-Bundle机制相关推荐
- android面试题总结加强
在加强版的基础上又再加强的android应用面试题集 有些补充略显臃肿,只为学习 1.activity的生命周期. 方法 描述 可被杀死 下一个 onCreate() 在activity第一次被创建的 ...
- 金三银四的面试黄金季节,Android面试题来了!
金三银四的跳槽季节,你准摆好了吗? 首先我们分享一个Android知识图谱. 下面是一些面试官基本必问的问题,请一定要去了解! 基础知识 – 四大组件(生命周期,使用场景,如何启动) java基础 – ...
- Android面试题收集(有具体答案)
Android面试题目及其答案 1.Android dvm的进程和Linux的进程, 应用程序的进程是否为同一个概念 DVM指dalivk的虚拟机.每个Android应用程序都在它自己的进程中执行,都 ...
- android+面试题
1.常用的存储方式有哪些?(概率50%) (五种,说出哪五种,五种存储方式什么情况下用.)注意sharepreferes对象支持读取不支持写入,写入引用Editor. SQLite: SQLite是一 ...
- Android面试题集1
1. 什么是Activity? 四大组件之一,一般的,一个用户交互界面对应一个activity setContentView() ,// 要显示的布局 , activity 是Context的子类,同 ...
- 19、android面试题整理(自己给自己充充电吧)
(转载,出处丢失,请原作者原谅,如有意见,私信我我会尽快删除本文) JAVA 1.GC是什么? 为什么要有GC? GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现 ...
- Android面试题及答案3
Java + Android面试题 JAVA相关基础知识 1.面向对象的特征有哪些方面 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面. 抽象并不打算 ...
- android 面试题(三)
JAVA相关基础知识 1.面向对象的特征有哪些方面 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面. 抽象并不打算了解全部问题,而只是选择其中的一 ...
- Android面试题和答案
71道经典Android面试题和答案 下列哪些语句关于内存回收的说明是正确的? (b ) A. 程序员必须创建一个线程来释放内存 B.内存回收程序负责释放无用内存 C.内存回收程序允许程序员直接释放内 ...
- Android面试题收集(有详细答案)
Android面试题目及其答案 1.Android dvm的进程和Linux的进程, 应用程序的进程是否为同一个概念 DVM指dalivk的虚拟机.每一个Android应用程序都在它自己的进程中运行, ...
最新文章
- Java中import及package的用法
- C# 类型实例化的语法糖--unity下诡异结果
- 比特币现金的一年回顾
- 通用联手谷歌,应用程序和语音助手将整合到车辆中
- 计算机网络(10)-----TCP的拥塞控制
- android activity 被notification启动,Android通知Notification全面剖析
- # 保持最外层获取焦点_大事件!沈阳爱尔白内障焕晶诊疗中心正式启用,两位PanOptix三焦点人工晶体植入患者清晰见证!...
- MySQL 语句优化 ICP
- 猎户星空否认停发高管薪资:无论遭遇怎样困难 都不会苛扣员工薪酬
- 协方差矩阵经线性变化可以变成不相关的
- VIM空格和TAB转换
- java怎么把程序写入持久化_如何将DataFrame持久化到Hive表?
- 在那里可以下载jar包?
- html动态表格用数组填充,自动填充数组中的HTML表格
- YII2框架AJAX请求报500错误的处理方法
- Echarts曲线渐变色lineStyle
- 大数据在 IoT 的应用
- Vue-Router学习记录
- 怎么让照片变年轻_如何用ps把人变年轻水嫩
- ATECC508A芯片开发笔记(八):ECDH算法配置方法、执行过程及实现原理