将捆绑包的内容打印到 Logcat?

如果你不能记住所有密钥的名字(即使只能打印密钥名字也很酷) ,那么有没有一种简单的方法可以把 Bundle的内容打印到 Logcat?

41335 次浏览

Bundle # keySet () 应该可以工作。

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

如果你想得到对象,你可以使用 Bundle#get(String key)(也在我答案顶部链接的相同文档中)。但是,请记住使用通用的 get()调用:

  • 你在和 Object 一起工作。如果您只是简单地打印到一个日志,toString()将被调用,一切都会好起来。但是,如果实际上希望使用密钥对,则需要进行 instanceof检查,以避免调用错误的方法。
  • 因为 toString 将被调用,所以如果您有一个特殊的 Object (例如 ArrayList,或者特殊的 Serialable/Parcelable 附加值) ,那么您很可能不会从打印输出中获得任何有用的东西。

通过按如下方式打印映射值,您可以获得更具体的信息:

for (String key : bundle.keySet())
{
Log.d("Bundle Debug", key + " = \"" + bundle.get(key) + "\"");
}

捆绑到字符串转换器:

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

示例用法:

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

产出:

details=Bundle{ RESPONSE_CODE => 5; }Bundle

注意,箭头 =>和分号 ;允许在键和值中提及空格。箭头前有一个空格,箭头后有一个空格,分号前没有空格,分号后有一个空格,{后有一个空格,}前有一个空格,所有其他的空格都在那里,因为它们都在键或值中。

我已经开发了一个名为 pretty-print的库,它是一个注释处理器,可以以一种很好的表格格式打印捆绑包的内容。 一定要去看看 Https://github.com/nullpointerguy/pretty-print

在 Kotlin,当它包含子包时的递归:

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

用法: myBundle.printDebugLog()

意识到这并不能准确地回答这个问题,但是我看到很多开发人员试图将内容转储到 logcat/游戏控制台,因为他们没有意识到他们可以在 Android Studio 调试器中设置,在调试时显示定制的对象呈现,当你遇到一个断点时。对于 Bundle,您可以采用这里其他答案中显示的代码类型,并将其作为自定义呈现程序应用,这样就不需要将转储通过管道传递给 logcat 和/或控制台。

(这些说明来自 Android Studio 3.1.3(2018年6月) ..。

  1. 选择“ File”,然后选择“ Settings”菜单选项/子选项。
  2. 在左侧的“设置”对话框中,向下钻取并选择“构建、执行、部署”、“调试器”、“数据视图”、“ Java 类型渲染器”。
  3. 对话框的右侧,其中写着“ Renderer name”,输入您希望与正在创建的渲染器标识的名称。
  4. 在对话框的右侧,输入‘ android.os. Bundle’,上面写着“ Apply renderer to object of type”。
  5. 在对话框的右侧,在“当呈现一个节点”部分下,选择“ Use following expression:”单选按钮。
  6. 在下面的文本字段中,键入以下..。
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. 按“应用”/“确定”按钮。

现在,当您运行应用程序时,遇到一个断点,该断点显示一个 android.os 类型的变量。Bundle 中,您将在调试器窗口的变量部分中看到上述代码生成的输出。

我还将包括一个屏幕截图,显示我上面描述的..。screenshot

科特林的解决方案:

val bundleFromNotifications: Bundle? = remoteMessage?.toIntent()?.extras
bundleFromNotifications?.keySet()?.forEach{
Log.d(LOG_TAG, it + "=> \"" + bundleFromNotifications.get(it) + "\"")
}

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

样本:

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

注意,它不能处理所有可能类型的值。你应该决定哪些是重要的,以何种方式显示。

返回文章页面简单捆绑到字符串在 Kotlin 的实现译者:

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

结果示例 {id=3, name="Jhon"}

Java8流一行程序:

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

诀窍: 访问 Bundle 的内容来具体化它,然后 bundle.toString()将格式化它的元素。

(我只是出于调试的目的才依赖它。)

AppWidgetProvider 中的示例,调用 newOptions.keySet():

    @Override
public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager,
int appWidgetId, Bundle newOptions) {
super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions);


newOptions.keySet(); // <-- reify the Bundle so .toString() will elaborate
Log.i(TAG, "*** WidgetOptionsChanged: " + newOptions);
}

结果:

*** WidgetOptionsChanged: Bundle[{appWidgetMaxHeight=137, appWidgetCategory=1, appWidgetMaxWidth=603, appWidgetMinHeight=82, appWidgetMinWidth=338, appWidgetSizes=[338.0x137.5, 603.5x82.0]}]

比:

*** WidgetOptionsChanged: Bundle[mParcelledData.dataSize=408]

科特林

如果你有 简单 Bundles (没有嵌套包) ,那么 Jerry 101的技巧已经让你走得很远了(见他们的评论为什么这样工作)。下面是一句俏皮话:

Log.d(TAG, "bundle: ${bundle?.also { it.keySet() }?: "N/A"}")

以上图片:

Bundle: Bundle [{ a = 42,s = hello,... }]

或者当捆绑销售是 null:

捆绑销售: 不行

如果你不确定上面的代码是否能够正常工作的话,可以使用稍微多一点的代码(使用其他人已经指出的 keySet函数)——也是一行代码:

Log.d(TAG, "bundle: ${bundle?.keySet()?.associateWith { bundle[it] }?: "N/A"}")

这将把捆绑包转换为 map 并打印

Bundle: { a = 42,s = hello,... }