@@ -141,6 +141,13 @@ public void shutdown() {
141141 private @ Nullable Set <Integer > mChildrenRemovedWhileTransitioning ;
142142 private boolean mPreventClipping ;
143143
144+ // 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
145+ private static final String [] removalTrackedChildrenIDs = {
146+ "native-freeze-screens-container" ,
147+ "guilds-bar-fast-list" ,
148+ };
149+
150+
144151 /**
145152 * Creates a new `ReactViewGroup` instance.
146153 *
@@ -641,6 +648,25 @@ public void onViewAdded(View child) {
641648
642649 @ Override
643650 public void onViewRemoved (View child ) {
651+ try {
652+ Object childNativeId = child .getTag (R .id .view_tag_native_id );
653+ if (nativeId instanceof String ) {
654+ String nativeID = (String ) nativeId ;
655+ boolean matches = java .util .Arrays .stream (removalTrackedChildrenIDs )
656+ .anyMatch (nativeID ::equals );
657+ if (matches ) {
658+ StringBuilder stackTraceBuilder = new StringBuilder ();
659+ for (StackTraceElement element : new Exception ().getStackTrace ()) {
660+ stackTraceBuilder .append ("\n at " ).append (element .toString ());
661+ }
662+ String stackTrace = stackTraceBuilder .toString ();
663+ FLog .e (ReactConstants .TAG , "onViewRemoved of one of the tracked children: " + nativeID + " with stack trace: " + "\n " + stackTrace );
664+ }
665+ }
666+ } catch (Exception e ) {
667+ FLog .e (ReactConstants .TAG , "Exception in getting onViewRemoved info: " + e .getMessage ());
668+ }
669+
644670 UiThreadUtil .assertOnUiThread ();
645671 checkViewClippingTag (child , Boolean .TRUE );
646672 if (!customDrawOrderDisabled ()) {
@@ -999,17 +1025,20 @@ protected void dispatchDraw(Canvas canvas) {
9991025 if (mOverflow != Overflow .VISIBLE || getTag (R .id .filter ) != null ) {
10001026 BackgroundStyleApplicator .clipToPaddingBox (this , canvas );
10011027 }
1002-
1028+
10031029 try {
10041030 super .dispatchDraw (canvas );
10051031 } catch (NullPointerException e ) {
1032+ String childrenCountInfo = "children count info: mAllChildrenCount:" + mAllChildrenCount + " getChildCount: " + getChildCount ();
1033+ String childrenViewInfo = describeChildren ();
10061034 String ancestry = null ;
10071035 try {
10081036 ancestry = describeViewAncestry (this );
10091037 } catch (Throwable ignore ) {}
1010- FLog .e (TAG , "NullPointerException in dispatchDraw of " + getClass ().getName () + ": " + e .getMessage () + "\n " + ancestry );
1038+ FLog .e (TAG , "NullPointerException in dispatchDraw of " + e .getStackTrace () + getClass ().getName () + ": " + e .getMessage () + "\n Failing view ancestry: " + ancestry );
1039+ FLog .e (TAG , "Child info: \n " + childrenCountInfo + "\n " + childrenViewInfo );
10111040 throw new NullPointerException (
1012- "NullPointerException in dispatchDraw of " + getClass ().getName () + ": " + e .getMessage () + "\n " + ancestry );
1041+ "NullPointerException in dispatchDraw of " + getClass ().getName () + ": " + e .getMessage () + "\n " + e . getStackTrace () );
10131042 }
10141043 }
10151044
@@ -1038,6 +1067,60 @@ private static String describeViewAncestry(View start) {
10381067 return sb .toString ();
10391068 }
10401069
1070+ // Helper function to describe children for debugging
1071+ private String describeChildren () {
1072+ final StringBuilder sb = new StringBuilder ();
1073+
1074+ sb .append (" Attached children: " );
1075+ int childCount = getChildCount ();
1076+ if (childCount == 0 ) {
1077+ sb .append (" (none)\n " );
1078+ } else {
1079+ for (int i = 0 ; i < childCount ; i ++) {
1080+ try {
1081+ View child = getChildAt (i );
1082+ if (child == null ) {
1083+ sb .append (" [" ).append (i ).append ("] NULL CHILD!\n " );
1084+ } else {
1085+ Object childNativeId = child .getTag (R .id .view_tag_native_id );
1086+ Object childTestId = child .getTag (R .id .react_test_id );
1087+ sb .append (" [" ).append (i ).append ("] " )
1088+ .append (child .getClass ().getSimpleName ())
1089+ .append (" id=" ).append (child .getId ());
1090+ if (childNativeId != null ) sb .append (" nativeID=" ).append (childNativeId );
1091+ if (childTestId != null ) sb .append (" testID=" ).append (childTestId );
1092+ sb .append (" parent=" ).append (child .getParent () != null ? "attached" : "DETACHED" );
1093+ sb .append ('\n' );
1094+ }
1095+ } catch (Exception e ) {
1096+ sb .append (" [" ).append (i ).append ("] ERROR: " ).append (e .getMessage ()).append ('\n' );
1097+ }
1098+ }
1099+ }
1100+
1101+ try {
1102+ // If removeClippedSubviews is enabled, show clipped children too
1103+ if (mRemoveClippedSubviews && mAllChildren != null && mAllChildrenCount > childCount ) {
1104+ sb .append (" Clipped children:\n " );
1105+ for (int i = 0 ; i < mAllChildrenCount ; i ++) {
1106+ View child = mAllChildren [i ];
1107+ if (child != null && child .getParent () == null ) {
1108+ Object childNativeId = child .getTag (R .id .view_tag_native_id );
1109+ sb .append (" [" ).append (i ).append ("] " )
1110+ .append (child .getClass ().getSimpleName ())
1111+ .append (" id=" ).append (child .getId ());
1112+ if (childNativeId != null ) sb .append (" nativeID=" ).append (childNativeId );
1113+ sb .append (" (CLIPPED)\n " );
1114+ }
1115+ }
1116+ }
1117+ } catch (Exception e ) {
1118+ sb .append (" Error describing clipped children: " ).append (e .getMessage ()).append ('\n' );
1119+ }
1120+
1121+ return sb .toString ();
1122+ }
1123+
10411124 @ Override
10421125 protected boolean drawChild (Canvas canvas , View child , long drawingTime ) {
10431126 boolean drawWithZ = child .getElevation () > 0 ;
0 commit comments