API21 released the PersistableBundle
which is a bundle that the system retains for various purposes (JobScheduler
jobs, ShortcutInfo
s etc). I'd like an easy way to convert the Bundle
's that are present in my old code to PersistableBundle
's...how can I do it?
Asked
Active
Viewed 3,702 times
9

Reuben Tanner
- 5,229
- 3
- 31
- 46
-
1I imagine you'll get a limited space for what you're saving. Anyway, instead of carpet bombing go for a precision strike i.e. save what you need to recover after a reboot and nothing else. /// `JobInfo.Builder.setExtras` accepts a `PersistableBundle` only. So if you create one directly you don't even touch regular `Bundle` and there's nothing to convert. – Eugen Pechanec Jul 28 '17 at 14:39
-
This is not an answer to the question. – Reuben Tanner Jul 31 '17 at 16:43
-
1That's why it's a comment. I'm just making sure you're not solving an artificial problem (a problem that shouldn't occur in the first place). – Eugen Pechanec Jul 31 '17 at 21:13
-
1As an example for a use case where the conversion is necessary, what if I wish to call a jobservice one a user clicks a notification? The notification would have a pending intent, where the extras are a `Bundle`, but it needs to pass the data again to the service, which uses a `PersistableBundle` – Allan W Dec 29 '17 at 19:13
3 Answers
7
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.

Arnold Balliu
- 1,099
- 10
- 21

Steppschuh
- 329
- 1
- 5
- 14
-
1This does not handle nested bundles properly, instead it flattens them out. In particular, `putIntoBundle` should be using `putPersistableBundle(key, ...)` instead of `putAll`. – Jaen May 16 '18 at 00:24
-
Is there any way to add `Parcelable` Object into `Persistable bundle`? – Richard Jan 16 '20 at 11:38
4
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);
}

Reuben Tanner
- 5,229
- 3
- 31
- 46
-1
Converting form Bundle to PersistableBundle
Bundle b = new Bundle();
PersistableBundle pb = new PersistableBundle(b);
Converting from PersistableBundle to Bundle
PersistableBundle pb = new PersistableBundle();
Bundle b= new Bundle();
b.putAll(pb);

Nikhil vijapur
- 9
- 1