68

Is there an easy way to print the contents of a Bundle to Logcat if you can't remember the names of all the keys (even being able to print just the key names would be cool)?

frogatto
  • 26,401
  • 10
  • 73
  • 111
Quasaur
  • 1,177
  • 1
  • 9
  • 27

10 Answers10

121

Bundle#keySet() should work.

for (String key: bundle.keySet())
{
  Log.d ("myApplication", key + " is a key in the bundle");
}

And if you want to get the Object, you can use Bundle#get(String key)(which is also in the same documentation I linked at the top of my answer). However, keep in mind using the generic get() call:

  • You're working with Object. If you're simply printing to a Log, toString() will be invoked and all will be fine. However, if you actually want to use the key's pair, you need to do instanceof checks to avoid calling the wrong method.
  • Since toString will be invoked, if you have a special Object (eg ArrayLists, or special Serializable/Parcelable extras) you're most likely not going to get anything useful from the printout.
A--C
  • 35,565
  • 10
  • 102
  • 90
  • 2
    I think you meant `bundle.keySet()` (since your docs link is fine); otherwise this is correct. – Eric Feb 19 '13 at 02:20
  • 1
    @Eric gah, silly errors. At least I spelled it correctly when I linked to it. – A--C Feb 19 '13 at 02:22
40

You can get more specific by printing the mapped value as follows:

for (String key : bundle.keySet())
{
    Log.d("Bundle Debug", key + " = \"" + bundle.get(key) + "\"");
}
Phil
  • 34,061
  • 21
  • 117
  • 154
22

Bundle-to-string converter:

public static String bundle2string(Bundle bundle) {
    if (bundle == null) {
        return null;
    }
    String string = "Bundle{";
    for (String key : bundle.keySet()) {
        string += " " + key + " => " + bundle.get(key) + ";";
    }
    string += " }Bundle";
    return string;
}

Example usage:

Log.d(TAG,"details="+bundle2string(details));

and output:

details=Bundle{ RESPONSE_CODE => 5; }Bundle

Note that the arrows => and semicolons ; let you mention spaces in the keys and values. One space before the arrow, one space after the arrow, no space before the semi-colon, one space after the semi-colon, one space after { and one space before }, and all other spaces are there because they are in the keys or values.

18446744073709551615
  • 14,600
  • 3
  • 82
  • 116
  • Good solution, but I would rather use a StringBuffer for better performance: `public static String bundle2string(Bundle bundle) { StringBuffer buf = new StringBuffer("Bundle{"); for (String key : bundle.keySet()) buf.append(" " + key + " => " + bundle.get(key) + ";"); buf.append(" }Bundle"); return buf.toString(); }` – Maurix Sep 05 '14 at 09:09
  • 1
    IMO performance is irrelevant to the purpose of _bundle2string()_, but even if we assume the opposite, according to http://stackoverflow.com/a/4649160/755804 , _String concatenation is translated into StringBuilder operations by the compiler._ I did not check it myself for Android; if someone cares to check this, please confirm or disprove. – 18446744073709551615 Sep 05 '14 at 09:35
  • 1
    @Maurix Since there are no threads involved, StringBuilder is better than StringBuffer : https://developer.android.com/reference/java/lang/StringBuffer.html – android developer Sep 29 '16 at 09:53
  • Note that some values might contain multiple-lines, so it can get problematic to print all of them in a single log entry. – Yoav Feuerstein Sep 19 '17 at 15:26
7

Realize that this isn't answering the question exactly, but I see allot of developers trying to dump the contents to logcat/console because they are not aware that they can set up in Android Studio debugger to display customized object rendering at debug time, when you hit a break point. And in the case of Bundle, you can take the type of code shown in the other answers here, and apply that as a custom renderer, so that you don't need to pipe the dump to logcat and/or the console.

(These instructions are from Android Studio 3.1.3 (June 2018) ...

  1. Select the "File" and then the "Settings" menu option/suboption.
  2. In the 'Settings' dialog, on the left side, drill-down and select "Build, Execution, Deployment", "Debugger", "Data Views", "Java Type Renderers".
  3. Right side of the dialog, where it says "Renderer name" enter a name you wish to identify with the renderer you are creating.
  4. Right side of the dialog, where it says "Apply renderer to objects of type", enter 'android.os.Bundle'.
  5. Right side of the dialog, under the "When rendering a node" section, select the "Use following expression:" radio button.
  6. In the text field below that, type in the following ...
StringBuilder builder = new StringBuilder();
for (String key : ((android.os.Bundle)this).keySet()) {
    Object value = ((android.os.Bundle)this).get(key);
    builder.append("[");
    builder.append(key);
    builder.append("]=[");
    builder.append(value);
    builder.append("](");
    builder.append((value != null) ? value.getClass().getSimpleName() : "null");
    builder.append("), ");
}
return builder.toString();
  1. Press 'Apply'/'OK' button.

Now, when you run your app, and you hit a breakpoint that shows a variable that is of type android.os.Bundle, you'll see the output generated from the above code, on the variables section of the debugger window.

I'll also include a screenshot, showing what I described above ... screenshot

Adrian Romanelli
  • 1,665
  • 16
  • 22
  • This is a really neat feature of Android Studio that I didn't know existed. Thank you! – Julian A. Dec 14 '18 at 22:03
  • @Julian A. You're welcome. Yeah, I've always been surprised its not talked about more, and wish that pre-created expressions for used often classes are not included with Android Studio, would save some time. FYI, Eclipse also has a similar feature as well, for those who use that IDE. – Adrian Romanelli Dec 18 '18 at 01:42
6

In Kotlin, recursive for when it contains child bundles:

/**
 * Recursively logs the contents of a [Bundle] for debugging.
 */
fun Bundle.printDebugLog(parentKey: String = "") {
    if (keySet().isEmpty()) {
        Log.d("printDebugLog", "$parentKey is empty")
    } else {
        for (key in keySet()) {
        when (val value = this[key]) {
                is Bundle -> value.printDebugLog(key)
                is Array<*> -> Log.d("printDebugLog", "$parentKey.$key : ${value.joinToString()}")
                else -> Log.d("printDebugLog", "$parentKey.$key : $value")
            }
        }
    }
}

Usage: myBundle.printDebugLog()

Frank
  • 11,222
  • 7
  • 58
  • 76
1

I have developed a library called pretty-print which annotation processor that prints the contents of the bundle in a nice table format. Do check it out https://github.com/NULLPointerGuy/pretty-print

Karthik Rk
  • 668
  • 1
  • 10
  • 19
1

A Kotlin solution:

val bundleFromNotifications: Bundle? = remoteMessage?.toIntent()?.extras
bundleFromNotifications?.keySet()?.forEach{
    Log.d(LOG_TAG, it + "=> \"" + bundleFromNotifications.get(it) + "\"")
}
Wai Ha Lee
  • 7,664
  • 52
  • 54
  • 80
ehivan24
  • 31
  • 6
1

Simple Bundle to String implementation in Kotlin:

val bundleToString = bundle.keySet()
            .joinToString(", ", "{", "}") { key ->
                "$key=${bundle[key]}"
            }

Example of result {id=3, name="Jhon"}

Vitor Hugo Schwaab
  • 1,265
  • 16
  • 27
  • 1
    Thanks, it works. The keys are arranged in alphabetical order (`keySet()` returns a sorted collection). – CoolMind Dec 23 '20 at 15:35
0

Solution in Kotlin:

fun Bundle.toPrintableString(): String {
    val sb = StringBuilder("{")
    var isFirst = true
    for (key in keySet()) {
        if (!isFirst)
            sb.append(',')
        else
            isFirst = false
        when (val value = get(key)) {
            is Bundle -> sb.append(key).append(':').append(value.toPrintableString())
            else -> sb.append(key).append(':').append(value)
            //TODO handle special cases if you wish
        }
    }
    sb.append('}')
    return sb.toString()
}

Sample:

    val bundle = Bundle()
    bundle.putString("asd", "qwe")
    bundle.putInt("zxc", 123)
    Log.d("AppLog", "bundle:${bundle.toPrintableString()}")

Note that it doesn't handle all possible types of values. You should decide which are important to show and in which way.

android developer
  • 106,412
  • 122
  • 641
  • 1,128
0

Java 8 stream one liner:

bundle.keySet().stream().forEach(k -> Log.d(TAG, k + " = " + bundle.get(k)));
DanCar
  • 11
  • 3