返回介绍

Bundle 存取数据的具体实现

发布于 2024-12-23 21:42:44 字数 4909 浏览 0 评论 0 收藏 0

布尔数据的存储源码如下:

/**
 * Inserts a Boolean value into the mapping of this Bundle, replacing
 * any existing value for the given key.  Either key or value may be null.
 *
 * @param key a String, or null
 * @param value a Boolean, or null
 */
void putBoolean(String key, boolean value) {
  unparcel();
  mMap.put(key, value);
}

这里的 mMap 就是 ArrayMap 了,存储数据就是把键值对保存到 ArrayMap 里。

布尔类型数据的读取源码如下:

/**
 * Returns the value associated with the given key, or false if
 * no mapping of the desired type exists for the given key.
 *
 * @param key a String
 * @return a boolean value
 */
boolean getBoolean(String key) {
  unparcel();
  if (DEBUG) Log.d(TAG, "Getting boolean in "+ Integer.toHexString(System.identityHashCode(this)));
  return getBoolean(key, false);
}

getBoolean(String key, boolean defaultValue) 的具体实现如下:

/**
 * Returns the value associated with the given key, or defaultValue if
 * no mapping of the desired type exists for the given key.
 *
 * @param key a String
 * @param defaultValue Value to return if key does not exist
 * @return a boolean value
 */
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 里读出保存的数据,并转换成对应的类型返回,当没找到数据或发生类型转换异常时返回缺省值。

注意到这里出现了一个方法: unparcel() ,它的具体源码如下:

/**
 * If the underlying data are stored as a Parcel, unparcel them
 * using the currently assigned class loader.
 */

/* package */ synchronized void unparcel() {
  if (mParcelledData == null) {
    if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
        + ": no parcelled data");
    return;
  }

  if (mParcelledData == EMPTY_PARCEL) {
    if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
        + ": empty");
    if (mMap == null) {
      mMap = new ArrayMap<String, Object>(1);
    } else {
      mMap.erase();
    }
    mParcelledData = null;
    return;
  }

  int N = mParcelledData.readInt();
  if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
      + ": reading " + N + " maps");
  if (N < 0) {
    return;
  }
  if (mMap == null) {
    mMap = new ArrayMap<String, Object>(N);
  } else {
    mMap.erase();
    mMap.ensureCapacity(N);
  }
  mParcelledData.readArrayMapInternal(mMap, N, mClassLoader);
  mParcelledData.recycle();
  mParcelledData = null;
  if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this)) + " final map: " + mMap);
}

先来看下 BaseBundle 中 mParcelledData 的定义:

/*
 * If mParcelledData is non-null, then mMap will be null and the
 * data are stored as a Parcel containing a Bundle.  When the data
 * are unparcelled, mParcelledData willbe set to null.
 */
Parcel mParcelledData = null;

在大部分情况下 mParcelledData 都是 null,因此 unparcel() 直接返回。当使用构造函数 public Bundle(Bundle b) 创建 Bundle 时,会给 mParcelledData 赋值,具体实现如下:

/**
 * Constructs a Bundle containing a copy of the mappings from the given
 * Bundle.
 *
 * @param b a Bundle to be copied.
 */
BaseBundle(BaseBundle b) {
  if (b.mParcelledData != null) {
    if (b.mParcelledData == EMPTY_PARCEL) {
      mParcelledData = EMPTY_PARCEL;
    } else {
      mParcelledData = Parcel.obtain();
      mParcelledData.appendFrom(b.mParcelledData, 0, b.mParcelledData.dataSize());
      mParcelledData.setDataPosition(0);
    }
  } else {
    mParcelledData = null;
  }

  if (b.mMap != null) {
    mMap = new ArrayMap<String, Object>(b.mMap);
  } else {
    mMap = null;
  }

  mClassLoader = b.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,具体是由以下代码片段实现的:

  int N = mParcelledData.readInt();
  if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
      + ": reading " + N + " maps");
  if (N < 0) {
    return;
  }
  if (mMap == null) {
    mMap = new ArrayMap<String, Object>(N);
  } else {
    mMap.erase();
    mMap.ensureCapacity(N);
  }
  mParcelledData.readArrayMapInternal(mMap, N, mClassLoader);
  mParcelledData.recycle();
  mParcelledData = null;

上面只是以布尔类型的数据为例分析了 Bundle 的存取过程,其他数据类型的存取原理相同,就不再赘述。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文