Skip to content

Commit 5d887e7

Browse files
authored
Add more logs to ReactViewGroup (#112)
* add more logs to ReactViewGroup dispatchDraw and onViewRemoved * clean up * fix formatting
1 parent 8393d9f commit 5d887e7

File tree

1 file changed

+84
-3
lines changed
  • packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view

1 file changed

+84
-3
lines changed

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java

Lines changed: 84 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import android.view.ViewParent;
2626
import android.view.ViewStructure;
2727
import android.view.animation.Animation;
28+
import android.util.Log;
2829
import androidx.annotation.Nullable;
2930
import com.facebook.common.logging.FLog;
3031
import com.facebook.infer.annotation.Assertions;
@@ -141,6 +142,13 @@ public void shutdown() {
141142
private @Nullable Set<Integer> mChildrenRemovedWhileTransitioning;
142143
private boolean mPreventClipping;
143144

145+
// debug values that will allow us to track down the source of the NPEs, related task: https://app.asana.com/1/236888843494340/project/1211388770903360/task/1211036733309341
146+
private static final String[] removalTrackedChildrenIDs = {
147+
"native-freeze-screens-container",
148+
"guilds-bar-fast-list",
149+
};
150+
151+
144152
/**
145153
* Creates a new `ReactViewGroup` instance.
146154
*
@@ -641,6 +649,21 @@ public void onViewAdded(View child) {
641649

642650
@Override
643651
public void onViewRemoved(View child) {
652+
try {
653+
Object childNativeId = child.getTag(R.id.view_tag_native_id);
654+
if (nativeId instanceof String) {
655+
String nativeID = (String) nativeId;
656+
boolean matches = java.util.Arrays.stream(removalTrackedChildrenIDs)
657+
.anyMatch(nativeID::equals);
658+
if (matches) {
659+
String stackTrace = android.util.Log.getStackTraceString(new Throwable());
660+
FLog.e(ReactConstants.TAG, "onViewRemoved of one of the tracked children: " + nativeID + " with stack trace: " + "\n" + stackTrace);
661+
}
662+
}
663+
} catch (Exception e) {
664+
FLog.e(ReactConstants.TAG, "Exception in getting onViewRemoved info: " + e.getMessage());
665+
}
666+
644667
UiThreadUtil.assertOnUiThread();
645668
checkViewClippingTag(child, Boolean.TRUE);
646669
if (!customDrawOrderDisabled()) {
@@ -999,17 +1022,21 @@ protected void dispatchDraw(Canvas canvas) {
9991022
if (mOverflow != Overflow.VISIBLE || getTag(R.id.filter) != null) {
10001023
BackgroundStyleApplicator.clipToPaddingBox(this, canvas);
10011024
}
1002-
1025+
10031026
try {
10041027
super.dispatchDraw(canvas);
10051028
} catch (NullPointerException e) {
1029+
String childrenCountInfo = "children count info: mAllChildrenCount:" + mAllChildrenCount + " getChildCount: " + getChildCount();
1030+
String childrenViewInfo = describeChildren();
10061031
String ancestry = null;
10071032
try {
10081033
ancestry = describeViewAncestry(this);
10091034
} catch (Throwable ignore) {}
1010-
FLog.e(TAG, "NullPointerException in dispatchDraw of " + getClass().getName() + ": " + e.getMessage() + "\n" + ancestry);
1035+
FLog.e(TAG, "NullPointerException in dispatchDraw of " + getClass().getName() + ": " + e.getMessage() + "\n Failing view ancestry: " + ancestry);
1036+
FLog.e(TAG, "Child info: \n" + childrenCountInfo + "\n" + childrenViewInfo);
1037+
String caughtErrorStackTrace = android.util.Log.getStackTraceString(e);
10111038
throw new NullPointerException(
1012-
"NullPointerException in dispatchDraw of " + getClass().getName() + ": " + e.getMessage() + "\n" + ancestry);
1039+
"NullPointerException in dispatchDraw of " + getClass().getName() + ": " + e.getMessage() + "\n" + caughtErrorStackTrace);
10131040
}
10141041
}
10151042

@@ -1038,6 +1065,60 @@ private static String describeViewAncestry(View start) {
10381065
return sb.toString();
10391066
}
10401067

1068+
// Helper function to describe children for debugging
1069+
private String describeChildren() {
1070+
final StringBuilder sb = new StringBuilder();
1071+
1072+
sb.append(" Attached children: ");
1073+
int childCount = getChildCount();
1074+
if (childCount == 0) {
1075+
sb.append(" (none)\n");
1076+
} else {
1077+
for (int i = 0; i < childCount; i++) {
1078+
try {
1079+
View child = getChildAt(i);
1080+
if (child == null) {
1081+
sb.append(" [").append(i).append("] NULL CHILD!\n");
1082+
} else {
1083+
Object childNativeId = child.getTag(R.id.view_tag_native_id);
1084+
Object childTestId = child.getTag(R.id.react_test_id);
1085+
sb.append(" [").append(i).append("] ")
1086+
.append(child.getClass().getSimpleName())
1087+
.append(" id=").append(child.getId());
1088+
if (childNativeId != null) sb.append(" nativeID=").append(childNativeId);
1089+
if (childTestId != null) sb.append(" testID=").append(childTestId);
1090+
sb.append(" parent=").append(child.getParent() != null ? "attached" : "DETACHED");
1091+
sb.append('\n');
1092+
}
1093+
} catch (Exception e) {
1094+
sb.append(" [").append(i).append("] ERROR: ").append(e.getMessage()).append('\n');
1095+
}
1096+
}
1097+
}
1098+
1099+
try {
1100+
// If removeClippedSubviews is enabled, show clipped children too
1101+
if (mRemoveClippedSubviews && mAllChildren != null && mAllChildrenCount > childCount) {
1102+
sb.append(" Clipped children:\n");
1103+
for (int i = 0; i < mAllChildrenCount; i++) {
1104+
View child = mAllChildren[i];
1105+
if (child != null && child.getParent() == null) {
1106+
Object childNativeId = child.getTag(R.id.view_tag_native_id);
1107+
sb.append(" [").append(i).append("] ")
1108+
.append(child.getClass().getSimpleName())
1109+
.append(" id=").append(child.getId());
1110+
if (childNativeId != null) sb.append(" nativeID=").append(childNativeId);
1111+
sb.append(" (CLIPPED)\n");
1112+
}
1113+
}
1114+
}
1115+
} catch (Exception e) {
1116+
sb.append(" Error describing clipped children: ").append(e.getMessage()).append('\n');
1117+
}
1118+
1119+
return sb.toString();
1120+
}
1121+
10411122
@Override
10421123
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
10431124
boolean drawWithZ = child.getElevation() > 0;

0 commit comments

Comments
 (0)