如何将 Bundle 转换为 PersistableBundle?

How can I convert a Bundle to a PersistableBundle?

API21 发布了 PersistableBundle which is a bundle that the system retains for various purposes (JobScheduler jobs, ShortcutInfos 等)。我想要一种简单的方法将旧代码中的 Bundle 转换为 PersistableBundle...我该怎么做?

从 API26 开始,没有办法轻松做到这一点,您必须手动验证这些值是否兼容:

private boolean bundleCanBePersisted(final Bundle extras) {
    if (extras == null) {
        return true;
    }

    Set<String> keys = extras.keySet();
    Iterator<String> it = keys.iterator();
    boolean allExtrasPersistable = true;
    while (it.hasNext()) {
        String key = it.next();
        boolean isPersistable = isPersistable(extras.get(key));

        if (!isPersistable) {
            LOGGER.warning("Non persistable value in bundle. " + bundleItemToString(key, extras));
        }

        allExtrasPersistable &= isPersistable;
    }
    return allExtrasPersistable;
}

/**
 * These are all the values that can be put into a PersistableBundle.
 */
private boolean isPersistable(final Object o) {
    return o == null
            || o instanceof PersistableBundle
            || o instanceof String
            || o instanceof String[]
            || o instanceof Boolean
            || o instanceof Boolean[]
            || o instanceof Double
            || o instanceof Double[]
            || o instanceof Integer
            || o instanceof Integer[]
            || o instanceof Long
            || o instanceof Long[];
}

private String bundleItemToString(final String key, final Bundle bundle) {
    Object value = bundle.get(key);
    Class<?> valueClazz = null;
    if (value != null) {
        valueClazz = value.getClass();
    }
    return String.format("[%s = %s (%s)]", key, value, valueClazz);
}

这是一个实际将 Bundle 转换为 PersistableBundle 并返回的实用程序:

/**
 * Creates a new {@link Bundle} based on the specified {@link PersistableBundle}.
 */
public static Bundle toBundle(PersistableBundle persistableBundle) {
    if (persistableBundle == null) {
        return null;
    }
    Bundle bundle = new Bundle();
    bundle.putAll(persistableBundle);
    return bundle;
}

/**
 * Creates a new {@link PersistableBundle} from the specified {@link Bundle}.
 * Will ignore all values that are not persistable, according
 * to {@link #isPersistableBundleType(Object)}.
 */
public static PersistableBundle toPersistableBundle(Bundle bundle) {
    if (bundle == null) {
        return null;
    }
    PersistableBundle persistableBundle = new PersistableBundle();
    for (String key : bundle.keySet()) {
        Object value = bundle.get(key);
        if (isPersistableBundleType(value)) {
            putIntoBundle(persistableBundle, key, value);
        }
    }
    return persistableBundle;
}

/**
 * Checks if the specified object can be put into a {@link PersistableBundle}.
 *
 * @see <a href="https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/os/PersistableBundle.java#49">PersistableBundle Implementation</a>
 */
public static boolean isPersistableBundleType(Object value) {
    return ((value instanceof PersistableBundle) ||
            (value instanceof Integer) || (value instanceof int[]) ||
            (value instanceof Long) || (value instanceof long[]) ||
            (value instanceof Double) || (value instanceof double[]) ||
            (value instanceof String) || (value instanceof String[]) ||
            (value instanceof Boolean) || (value instanceof boolean[])
    );
}

/**
 * Attempts to insert the specified key value pair into the specified bundle.
 *
 * @throws IllegalArgumentException if the value type can not be put into the bundle.
 */
public static void putIntoBundle(BaseBundle baseBundle, String key, Object value) throws IllegalArgumentException {
    if (value == null) {
        throw new IllegalArgumentException("Unable to determine type of null values");
    } else if (value instanceof Integer) {
        baseBundle.putInt(key, (int) value);
    } else if (value instanceof int[]) {
        baseBundle.putIntArray(key, (int[]) value);
    } else if (value instanceof Long) {
        baseBundle.putLong(key, (long) value);
    } else if (value instanceof long[]) {
        baseBundle.putLongArray(key, (long[]) value);
    } else if (value instanceof Double) {
        baseBundle.putDouble(key, (double) value);
    } else if (value instanceof double[]) {
        baseBundle.putDoubleArray(key, (double[]) value);
    } else if (value instanceof String) {
        baseBundle.putString(key, (String) value);
    } else if (value instanceof String[]) {
        baseBundle.putStringArray(key, (String[]) value);
    } else if (value instanceof Boolean) {
        baseBundle.putBoolean(key, (boolean) value);
    } else if (value instanceof boolean[]) {
        baseBundle.putBooleanArray(key, (boolean[]) value);
    } else if (value instanceof PersistableBundle) {
        if (baseBundle instanceof PersistableBundle)
            ((PersistableBundle) baseBundle).putPersistableBundle(key, (PersistableBundle)value);
        else if (baseBundle instanceof Bundle)
            ((Bundle) baseBundle).putBundle(key, toBundle((PersistableBundle) value));
    } else {
        throw new IllegalArgumentException("Objects of type " + value.getClass().getSimpleName()
                + " can not be put into a " + BaseBundle.class.getSimpleName());
    }
}

您可以在 this gist 中找到完整的 class 和单元测试。

将表单 Bundle 转换为 PersistableBundle

Bundle b = new Bundle();
PersistableBundle pb = new PersistableBundle(b);

从 PersistableBundle 转换为 Bundle

PersistableBundle pb = new PersistableBundle();
Bundle b= new Bundle();
b.putAll(pb);