TransactionTooLargeException问题定位基础流程

/ 0评 / 0

为什么会TransactionTooLargeException

Activity/Fragment之间通过Bundle传递的参数过大导致,可能出现在启动界面或者界面开始保存数据onActivitySaveInstanceState/onFragmentSaveInstanceState中

如何判断Bundle的大小以及参数的大小

通过Parcel的dataSize方法即可获取对应Bundle的大小

/**
 * Measure the size of a typed [Bundle] when written to a [Parcel].
 *
 * @param bundle to measure
 * @return size when written to parcel in bytes
 */
fun sizeAsParcel(bundle: Bundle): Int {
    val parcel = Parcel.obtain()
    try {
        parcel.writeBundle(bundle)
        return parcel.dataSize()
    } finally {
        parcel.recycle()
    }
}

/**
 * Measure the size of a [Parcelable] when written to a [Parcel].
 *
 * @param parcelable to measure
 * @return size of parcel in bytes
 */
fun sizeAsParcel(parcelable: Parcelable): Int {
    val parcel = Parcel.obtain()
    try {
        parcel.writeParcelable(parcelable, 0)
        return parcel.dataSize()
    } finally {
        parcel.recycle()
    }
}

只需要获取参数大小,我们可以通过删除一个key然后计算一次大小,差值则为对应key的内存大小,当然,我们需要在计算完毕以后,把数据写回原来的Bundle

/**
 * Measure the sizes of all the values in a typed [Bundle] when written to a
 * [Parcel]. Returns a map from keys to the sizes, in bytes, of the associated values in
 * the Bundle.
 *
 * @param bundle to measure
 * @return a map from keys to value sizes in bytes
 */
fun sizeTreeFromBundle(bundle: Bundle): SizeTree {
    val results = ArrayList<SizeTree>(bundle.size())
    // We measure the totalSize of each value by measuring the total totalSize of the bundle before and
    // after removing that value and calculating the difference. We make a copy of the original
    // bundle so we can put all the original values back at the end. It's not possible to
    // carry out the measurements on the copy because of the way Android parcelables work
    // under the hood where certain objects are actually stored as references.
    val copy = Bundle(bundle)
    try {
        var bundleSize = sizeAsParcel(bundle)
        // Iterate over copy's keys because we're removing those of the original bundle
        for (key in copy.keySet()) {
            bundle.remove(key)
            val newBundleSize = sizeAsParcel(bundle)
            val valueSize = bundleSize - newBundleSize
            results.add(SizeTree(key, valueSize, emptyList()))
            bundleSize = newBundleSize
        }
    } finally {
        // Put everything back into original bundle
        bundle.putAll(copy)
    }
    return SizeTree("Bundle" + System.identityHashCode(bundle), sizeAsParcel(bundle), results)
}

如何自动判断

Activity可以通过Application.ActivityLifecycleCallbacks来监听,Fragment可以通过FragmentManager的registerFragmentLifecycleCallbacks来监听,详见https://27house.cn/archives/2356

see https://github.com/guardian/toolargetool/

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注