How can I convert a Bundle to a PersistableBundle?

Here's a utility that actually converts a Bundle to a PersistableBundle and back:

/**
 * 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());
    }
}

You can find the complete class and unit tests in this gist.


As of API26, there is no way exposed to easily do this, you have to manually verify that the values are compatible:

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);
}