Browse Source

Fix crash when title component is destroyed right after being attached

Edge case when preDrawListener callback is invoked after ViewController is destroyed
Guy Carmeli 4 years ago
parent
commit
39ee1701fd

+ 4
- 2
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/TitleBarReactViewController.java View File

@@ -21,8 +21,10 @@ public class TitleBarReactViewController extends ViewController<TitleBarReactVie
21 21
     @Override
22 22
     public void onViewAppeared() {
23 23
         super.onViewAppeared();
24
-        runOnPreDraw(view -> view.setLayoutParams(view.getLayoutParams()));
25
-        getView().sendComponentStart();
24
+        if (!isDestroyed()) {
25
+            runOnPreDraw(view -> view.setLayoutParams(view.getLayoutParams()));
26
+            getView().sendComponentStart();
27
+        }
26 28
     }
27 29
 
28 30
     @Override

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ViewController.java View File

@@ -296,7 +296,7 @@ public abstract class ViewController<T extends ViewGroup> implements ViewTreeObs
296 296
     }
297 297
 
298 298
     void runOnPreDraw(Func1<T> task) {
299
-        UiUtils.runOnPreDrawOnce(getView(), () -> task.run(getView()));
299
+        if (!isDestroyed) UiUtils.runOnPreDrawOnce(getView(), task);
300 300
     }
301 301
 
302 302
     public abstract void sendOnNavigationButtonPressed(String buttonId);

+ 19
- 0
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ViewControllerTest.java View File

@@ -15,6 +15,7 @@ import com.reactnativenavigation.parse.Options;
15 15
 import com.reactnativenavigation.parse.params.Bool;
16 16
 import com.reactnativenavigation.parse.params.NullBool;
17 17
 import com.reactnativenavigation.utils.CommandListenerAdapter;
18
+import com.reactnativenavigation.utils.Functions;
18 19
 import com.reactnativenavigation.viewcontrollers.stack.StackController;
19 20
 import com.reactnativenavigation.views.Component;
20 21
 
@@ -112,6 +113,24 @@ public class ViewControllerTest extends BaseTest {
112 113
         assertThat(uut.findController("uut")).isEqualTo(uut);
113 114
     }
114 115
 
116
+    @Test
117
+    public void runOnPreDraw() {
118
+        Functions.Func1<View> task = Mockito.mock(Functions.Func1.class);
119
+        uut.runOnPreDraw(task);
120
+        dispatchPreDraw(uut.getView());
121
+        verify(task).run(uut.getView());
122
+    }
123
+
124
+    @Test
125
+    public void runOnPreDraw_doesNotInvokeTaskIfControllerIsDestroyed() {
126
+        Functions.Func1<View> task = Mockito.mock(Functions.Func1.class);
127
+        uut.runOnPreDraw(task);
128
+        View view = uut.getView();
129
+        uut.destroy();
130
+        dispatchPreDraw(view);
131
+        verify(task, times(1)).run(view);
132
+    }
133
+
115 134
     @Test
116 135
     public void onChildViewAdded_delegatesToYellowBoxDelegate() {
117 136
         View child = new View(activity);