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
     @Override
21
     @Override
22
     public void onViewAppeared() {
22
     public void onViewAppeared() {
23
         super.onViewAppeared();
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
     @Override
30
     @Override

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

296
     }
296
     }
297
 
297
 
298
     void runOnPreDraw(Func1<T> task) {
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
     public abstract void sendOnNavigationButtonPressed(String buttonId);
302
     public abstract void sendOnNavigationButtonPressed(String buttonId);

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

15
 import com.reactnativenavigation.parse.params.Bool;
15
 import com.reactnativenavigation.parse.params.Bool;
16
 import com.reactnativenavigation.parse.params.NullBool;
16
 import com.reactnativenavigation.parse.params.NullBool;
17
 import com.reactnativenavigation.utils.CommandListenerAdapter;
17
 import com.reactnativenavigation.utils.CommandListenerAdapter;
18
+import com.reactnativenavigation.utils.Functions;
18
 import com.reactnativenavigation.viewcontrollers.stack.StackController;
19
 import com.reactnativenavigation.viewcontrollers.stack.StackController;
19
 import com.reactnativenavigation.views.Component;
20
 import com.reactnativenavigation.views.Component;
20
 
21
 
112
         assertThat(uut.findController("uut")).isEqualTo(uut);
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
     @Test
134
     @Test
116
     public void onChildViewAdded_delegatesToYellowBoxDelegate() {
135
     public void onChildViewAdded_delegatesToYellowBoxDelegate() {
117
         View child = new View(activity);
136
         View child = new View(activity);