Debugging my app with strange results on Samsung phones, which I don't have physical access to. I'd like to ask a user to run an instrumented App to help debug. My App gets a view
that has an unknown (to me ;-) hierarchy in it (ViewGroups
etc). Is there a way to "walk" a View
and print out to a string / ddms
all the components in the View
(etc ViewGroups
in it etc)?
This would be akin to HierarchyViewer
tool - if I had adb
level access to the device.
Update: I guess I could use the method
void dumpViewHierarchyWithProperties(Context context, ViewGroup group, BufferedWriter out, int level)
from the ViewDebug.java
Android OS sources ...
Anyone have a better idea?
Thanks!
Here's the utility function I just made for this purpose:
public static void printViewHierarchy(ViewGroup vg, String prefix) {
for (int i = 0; i < vg.getChildCount(); i++) {
View v = vg.getChildAt(i);
String desc = prefix + " | " + "[" + i + "/" + (vg.getChildCount()-1) + "] "+ v.getClass().getSimpleName() + " " + v.getId();
Log.v("x", desc);
if (v instanceof ViewGroup) {
printViewHierarchy((ViewGroup)v, desc);
}
}
}
I've created utility method which returns hierarchy in a pretty printed way with human readable view ids. Here is an example of the output:
[LinearLayout] no_id
[CardView] com.example:id/card_view
[RelativeLayout] no_id
[LinearLayout] com.example:id/image_container
[AppCompatImageView] com.example:id/incident_icon
[CustomTextView] com.example:id/road_number
[RelativeLayout] no_id
[CustomTextView] com.example:id/distance_to_user
[CustomTextView] com.example:id/obstruction_title
[CustomTextView] com.example:id/road_direction
[CustomTextView] com.example:id/obstruction_description
[AppCompatImageView] com.example:id/security_related
Here is the utility method:
public static String getViewHierarchy(@NonNull View v) {
StringBuilder desc = new StringBuilder();
getViewHierarchy(v, desc, 0);
return desc.toString();
}
private static void getViewHierarchy(View v, StringBuilder desc, int margin) {
desc.append(getViewMessage(v, margin));
if (v instanceof ViewGroup) {
margin++;
ViewGroup vg = (ViewGroup) v;
for (int i = 0; i < vg.getChildCount(); i++) {
getViewHierarchy(vg.getChildAt(i), desc, margin);
}
}
}
private static String getViewMessage(View v, int marginOffset) {
String repeated = new String(new char[marginOffset]).replace("\0", " ");
try {
String resourceId = v.getResources() != null ? (v.getId() > 0 ? v.getResources().getResourceName(v.getId()) : "no_id") : "no_resources";
return repeated + "[" + v.getClass().getSimpleName() + "] " + resourceId + "\n";
} catch (Resources.NotFoundException e) {
return repeated + "[" + v.getClass().getSimpleName() + "] name_not_found\n";
}
}
Tip: we use this method to add view hierarchies to some crash reports. In some cases it is really helpful.
The format of other outputs dissatisfied my eyes and some codes where an overhead. So, I improved the output with:
/**
* Prints the view hierarchy.
*/
public static void printViewHierarchy(ViewGroup parent, String intent) {
for (int i = 0, max = parent.getChildCount(), numLenght = (max + "").length(); i < max; i++) {
View child = parent.getChildAt(i);
String childString = child.getClass().getSimpleName() + " " + child.getId();
String format = "|— %0" + numLenght + "d/%0" + numLenght + "d %s";
Log.d("debug", intent + String.format(format, i + 1, max, childString));
if (child instanceof ViewGroup)
printViewHierarchy((ViewGroup) child, intent + " ");
}
}
to:
|— 1/4 ScrollView 2131296482
|— 2/4 MaterialTextView 2131296445
|— 3/4 FloatingActionButton 2131296374
|— 4/4 MaterialTextView 2131296363
|— 1/4 ScrollView 2131296482
|— 1/1 LinearLayout 2129243036
|— 01/74 RelativeLayout 2131296449
|— 1/4 MaterialCheckBox 2131296332
|— 2/4 MaterialTextView 2131296547
|— 3/4 MaterialTextView 2131296531
|— 4/4 AppCompatImageButton 2131296462
|— 02/74 RelativeLayout 2131296449
|— 1/4 MaterialCheckBox 2131296332
|— 2/4 MaterialTextView 2131296547
|— 3/4 MaterialTextView 2131296531
|— 4/4 AppCompatImageButton 2131296462
|— ...
|— 74/74 RelativeLayout 2131296449
|— 1/4 MaterialCheckBox 2131296332
|— 2/4 MaterialTextView 2131296547
|— 3/4 MaterialTextView 2131296531
|— 4/4 AppCompatImageButton 2131296462
|— 2/4 MaterialTextView 2131296445
|— 3/4 FloatingActionButton 2131296374
|— 4/4 MaterialTextView 2131296363
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With