Browse Source

Destroy views when activity is destroyed and reloaded

Guy Carmeli 6 years ago
parent
commit
096481e496

+ 18
- 10
lib/android/app/src/main/java/com/reactnativenavigation/NavigationActivity.java View File

6
 import android.view.KeyEvent;
6
 import android.view.KeyEvent;
7
 
7
 
8
 import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
8
 import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
9
+import com.reactnativenavigation.presentation.OverlayManager;
10
+import com.reactnativenavigation.react.ReactGateway;
9
 import com.reactnativenavigation.utils.CommandListenerAdapter;
11
 import com.reactnativenavigation.utils.CommandListenerAdapter;
10
 import com.reactnativenavigation.viewcontrollers.Navigator;
12
 import com.reactnativenavigation.viewcontrollers.Navigator;
11
 
13
 
12
 public class NavigationActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {
14
 public class NavigationActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {
13
-	private Navigator navigator;
15
+	protected Navigator navigator;
14
 
16
 
15
 	@Override
17
 	@Override
16
 	protected void onCreate(@Nullable Bundle savedInstanceState) {
18
 	protected void onCreate(@Nullable Bundle savedInstanceState) {
17
 		super.onCreate(savedInstanceState);
19
 		super.onCreate(savedInstanceState);
18
-		app().getReactGateway().onActivityCreated(this);
19
-		navigator = new Navigator(this);
20
+		navigator = new Navigator(this, new OverlayManager());
21
+		getReactGateway().onActivityCreated(this);
22
+		getReactGateway().addReloadListener(navigator);
20
 		setContentView(navigator.getView());
23
 		setContentView(navigator.getView());
21
 	}
24
 	}
22
 
25
 
23
-	@Override
26
+    @Override
24
 	protected void onResume() {
27
 	protected void onResume() {
25
 		super.onResume();
28
 		super.onResume();
26
-		app().getReactGateway().onActivityResumed(this);
29
+		getReactGateway().onActivityResumed(this);
27
 	}
30
 	}
28
 
31
 
29
 	@Override
32
 	@Override
30
 	protected void onPause() {
33
 	protected void onPause() {
31
 		super.onPause();
34
 		super.onPause();
32
-		app().getReactGateway().onActivityPaused(this);
35
+		getReactGateway().onActivityPaused(this);
33
 	}
36
 	}
34
 
37
 
35
 	@Override
38
 	@Override
36
 	protected void onDestroy() {
39
 	protected void onDestroy() {
37
 		super.onDestroy();
40
 		super.onDestroy();
38
 		navigator.destroy();
41
 		navigator.destroy();
39
-		app().getReactGateway().onActivityDestroyed(this);
42
+		getReactGateway().removeReloadListener(navigator);
43
+		getReactGateway().onActivityDestroyed(this);
40
 	}
44
 	}
41
 
45
 
42
 	@Override
46
 	@Override
48
 
52
 
49
 	@Override
53
 	@Override
50
 	public void onBackPressed() {
54
 	public void onBackPressed() {
51
-		app().getReactGateway().onBackPressed();
55
+		getReactGateway().onBackPressed();
52
 	}
56
 	}
53
 
57
 
54
 	@Override
58
 	@Override
55
 	public boolean onKeyUp(final int keyCode, final KeyEvent event) {
59
 	public boolean onKeyUp(final int keyCode, final KeyEvent event) {
56
-		return app().getReactGateway().onKeyUp(keyCode) || super.onKeyUp(keyCode, event);
60
+		return getReactGateway().onKeyUp(keyCode) || super.onKeyUp(keyCode, event);
57
 	}
61
 	}
58
 
62
 
63
+    public ReactGateway getReactGateway() {
64
+        return app().getReactGateway();
65
+    }
66
+
59
 	private NavigationApplication app() {
67
 	private NavigationApplication app() {
60
 		return (NavigationApplication) getApplication();
68
 		return (NavigationApplication) getApplication();
61
 	}
69
 	}
62
 
70
 
63
-	public Navigator getNavigator() {
71
+    public Navigator getNavigator() {
64
 		return navigator;
72
 		return navigator;
65
 	}
73
 	}
66
 }
74
 }

+ 23
- 8
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/Navigator.java View File

14
 import com.reactnativenavigation.parse.Options;
14
 import com.reactnativenavigation.parse.Options;
15
 import com.reactnativenavigation.presentation.NavigationOptionsListener;
15
 import com.reactnativenavigation.presentation.NavigationOptionsListener;
16
 import com.reactnativenavigation.presentation.OverlayManager;
16
 import com.reactnativenavigation.presentation.OverlayManager;
17
+import com.reactnativenavigation.react.JsDevReloadHandler;
17
 import com.reactnativenavigation.utils.CommandListenerAdapter;
18
 import com.reactnativenavigation.utils.CommandListenerAdapter;
18
 import com.reactnativenavigation.utils.CompatUtils;
19
 import com.reactnativenavigation.utils.CompatUtils;
19
 import com.reactnativenavigation.viewcontrollers.modal.ModalPresenter;
20
 import com.reactnativenavigation.viewcontrollers.modal.ModalPresenter;
22
 import java.util.Collection;
23
 import java.util.Collection;
23
 import java.util.Collections;
24
 import java.util.Collections;
24
 
25
 
25
-public class Navigator extends ParentController {
26
+public class Navigator extends ParentController implements JsDevReloadHandler.ReloadListener {
26
 
27
 
27
     public interface CommandListener {
28
     public interface CommandListener {
28
         void onSuccess(String childId);
29
         void onSuccess(String childId);
34
     private ViewController root;
35
     private ViewController root;
35
     private FrameLayout rootLayout;
36
     private FrameLayout rootLayout;
36
     private FrameLayout contentLayout;
37
     private FrameLayout contentLayout;
37
-    private OverlayManager overlayManager = new OverlayManager();
38
+    private final OverlayManager overlayManager;
38
     private Options defaultOptions = new Options();
39
     private Options defaultOptions = new Options();
39
 
40
 
40
-    public Navigator(final Activity activity) {
41
+    public Navigator(final Activity activity, OverlayManager overlayManager) {
41
         super(activity, "navigator" + CompatUtils.generateViewId(), new Options());
42
         super(activity, "navigator" + CompatUtils.generateViewId(), new Options());
42
         modalStack = new ModalStack(new ModalPresenter(new ModalAnimator(activity)));
43
         modalStack = new ModalStack(new ModalPresenter(new ModalAnimator(activity)));
44
+        this.overlayManager = overlayManager;
43
     }
45
     }
44
 
46
 
45
     public FrameLayout getContentLayout() {
47
     public FrameLayout getContentLayout() {
68
         return modalStack.handleBack(listener, root);
70
         return modalStack.handleBack(listener, root);
69
     }
71
     }
70
 
72
 
73
+    @Override
74
+    public void onReload() {
75
+        destroyViews();
76
+    }
77
+
71
     @Override
78
     @Override
72
     public void destroy() {
79
     public void destroy() {
73
-        modalStack.dismissAllModals(new CommandListenerAdapter(), root);
80
+        destroyViews();
74
         super.destroy();
81
         super.destroy();
75
     }
82
     }
76
 
83
 
84
+    private void destroyViews() {
85
+        destroyRoot();
86
+        overlayManager.destroy();
87
+        modalStack.dismissAllModals(new CommandListenerAdapter(), root);
88
+    }
89
+
90
+    private void destroyRoot() {
91
+        if (root != null) root.destroy();
92
+        root = null;
93
+    }
94
+
77
     @Override
95
     @Override
78
     public void sendOnNavigationButtonPressed(String buttonId) {
96
     public void sendOnNavigationButtonPressed(String buttonId) {
79
 
97
 
80
     }
98
     }
81
 
99
 
82
     public void setRoot(final ViewController viewController, Promise promise) {
100
     public void setRoot(final ViewController viewController, Promise promise) {
83
-        if (root != null) {
84
-            root.destroy();
85
-        }
86
-
101
+        destroyRoot();
87
         root = viewController;
102
         root = viewController;
88
         contentLayout.addView(viewController.getView());
103
         contentLayout.addView(viewController.getView());
89
         if (viewController.options.animations.startApp.hasValue()) {
104
         if (viewController.options.animations.startApp.hasValue()) {

+ 5
- 0
lib/android/app/src/test/java/com/reactnativenavigation/BaseTest.java View File

11
 import org.junit.*;
11
 import org.junit.*;
12
 import org.junit.runner.*;
12
 import org.junit.runner.*;
13
 import org.robolectric.*;
13
 import org.robolectric.*;
14
+import org.robolectric.android.controller.ActivityController;
14
 import org.robolectric.annotation.*;
15
 import org.robolectric.annotation.*;
15
 
16
 
16
 import static org.assertj.core.api.Java6Assertions.*;
17
 import static org.assertj.core.api.Java6Assertions.*;
32
         return Robolectric.setupActivity(AppCompatActivity.class);
33
         return Robolectric.setupActivity(AppCompatActivity.class);
33
     }
34
     }
34
 
35
 
36
+    public <T extends AppCompatActivity> ActivityController<T> newActivityController(Class<T> clazz) {
37
+        return Robolectric.buildActivity(clazz);
38
+    }
39
+
35
     public void assertIsChild(ViewGroup parent, View child) {
40
     public void assertIsChild(ViewGroup parent, View child) {
36
         assertThat(parent).isNotNull();
41
         assertThat(parent).isNotNull();
37
         assertThat(child).isNotNull();
42
         assertThat(child).isNotNull();

+ 18
- 0
lib/android/app/src/test/java/com/reactnativenavigation/TestActivity.java View File

1
+package com.reactnativenavigation;
2
+
3
+import com.reactnativenavigation.react.ReactGateway;
4
+import com.reactnativenavigation.viewcontrollers.Navigator;
5
+
6
+import org.mockito.Mockito;
7
+
8
+public class TestActivity extends NavigationActivity {
9
+
10
+    @Override
11
+    public ReactGateway getReactGateway() {
12
+        return Mockito.mock(ReactGateway.class);
13
+    }
14
+
15
+    public void setNavigator(Navigator navigator) {
16
+        this.navigator = navigator;
17
+    }
18
+}

+ 38
- 5
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/NavigatorTest.java View File

1
 package com.reactnativenavigation.viewcontrollers;
1
 package com.reactnativenavigation.viewcontrollers;
2
 
2
 
3
-import android.app.Activity;
4
 import android.support.annotation.NonNull;
3
 import android.support.annotation.NonNull;
5
 
4
 
6
 import com.reactnativenavigation.BaseTest;
5
 import com.reactnativenavigation.BaseTest;
6
+import com.reactnativenavigation.TestActivity;
7
 import com.reactnativenavigation.mocks.ImageLoaderMock;
7
 import com.reactnativenavigation.mocks.ImageLoaderMock;
8
 import com.reactnativenavigation.mocks.MockPromise;
8
 import com.reactnativenavigation.mocks.MockPromise;
9
 import com.reactnativenavigation.mocks.SimpleComponentViewController;
9
 import com.reactnativenavigation.mocks.SimpleComponentViewController;
14
 import com.reactnativenavigation.parse.Options;
14
 import com.reactnativenavigation.parse.Options;
15
 import com.reactnativenavigation.parse.params.Bool;
15
 import com.reactnativenavigation.parse.params.Bool;
16
 import com.reactnativenavigation.parse.params.Text;
16
 import com.reactnativenavigation.parse.params.Text;
17
+import com.reactnativenavigation.presentation.OverlayManager;
17
 import com.reactnativenavigation.utils.CommandListenerAdapter;
18
 import com.reactnativenavigation.utils.CommandListenerAdapter;
18
 import com.reactnativenavigation.utils.CompatUtils;
19
 import com.reactnativenavigation.utils.CompatUtils;
19
 import com.reactnativenavigation.utils.ImageLoader;
20
 import com.reactnativenavigation.utils.ImageLoader;
23
 import com.reactnativenavigation.viewcontrollers.topbar.TopBarController;
24
 import com.reactnativenavigation.viewcontrollers.topbar.TopBarController;
24
 
25
 
25
 import org.junit.Test;
26
 import org.junit.Test;
27
+import org.mockito.Mockito;
28
+import org.robolectric.android.controller.ActivityController;
26
 
29
 
27
 import java.util.Arrays;
30
 import java.util.Arrays;
28
 
31
 
36
 import static org.mockito.Mockito.when;
39
 import static org.mockito.Mockito.when;
37
 
40
 
38
 public class NavigatorTest extends BaseTest {
41
 public class NavigatorTest extends BaseTest {
39
-    private Activity activity;
42
+    private TestActivity activity;
40
     private Navigator uut;
43
     private Navigator uut;
41
     private StackController parentController;
44
     private StackController parentController;
42
     private SimpleViewController child1;
45
     private SimpleViewController child1;
46
     private ViewController child5;
49
     private ViewController child5;
47
     private Options tabOptions = OptionHelper.createBottomTabOptions();
50
     private Options tabOptions = OptionHelper.createBottomTabOptions();
48
     private ImageLoader imageLoaderMock;
51
     private ImageLoader imageLoaderMock;
52
+    private ActivityController<TestActivity> activityController;
53
+    private OverlayManager overlayManager;
49
 
54
 
50
     @Override
55
     @Override
51
     public void beforeEach() {
56
     public void beforeEach() {
52
         super.beforeEach();
57
         super.beforeEach();
58
+        overlayManager = Mockito.mock(OverlayManager.class);
53
         imageLoaderMock = ImageLoaderMock.mock();
59
         imageLoaderMock = ImageLoaderMock.mock();
54
-        activity = newActivity();
55
-        uut = new Navigator(activity);
60
+        activityController = newActivityController(TestActivity.class);
61
+        activity = activityController.create().get();
62
+        uut = new Navigator(activity, overlayManager);
63
+        activity.setNavigator(uut);
64
+
56
         parentController = spy(newStack());
65
         parentController = spy(newStack());
57
         parentController.ensureViewIsCreated();
66
         parentController.ensureViewIsCreated();
58
         child1 = new SimpleViewController(activity, "child1", tabOptions);
67
         child1 = new SimpleViewController(activity, "child1", tabOptions);
61
         child4 = new SimpleViewController(activity, "child4", tabOptions);
70
         child4 = new SimpleViewController(activity, "child4", tabOptions);
62
         child5 = new SimpleViewController(activity, "child5", tabOptions);
71
         child5 = new SimpleViewController(activity, "child5", tabOptions);
63
         activity.setContentView(uut.getView());
72
         activity.setContentView(uut.getView());
73
+
74
+        activityController.visible();
64
     }
75
     }
65
 
76
 
66
     @Test
77
     @Test
80
     @Test
91
     @Test
81
     public void hasUniqueId() {
92
     public void hasUniqueId() {
82
         assertThat(uut.getId()).startsWith("navigator");
93
         assertThat(uut.getId()).startsWith("navigator");
83
-        assertThat(new Navigator(activity).getId()).isNotEqualTo(uut.getId());
94
+        assertThat(new Navigator(activity, overlayManager).getId()).isNotEqualTo(uut.getId());
84
     }
95
     }
85
 
96
 
86
     @Test
97
     @Test
447
         });
458
         });
448
     }
459
     }
449
 
460
 
461
+    @Test
462
+    public void destroy_destroyedRoot() {
463
+        parentController.options.animations.startApp.enable = new Bool(false);
464
+        uut.setRoot(parentController, new MockPromise());
465
+        activityController.destroy();
466
+        verify(parentController, times(1)).destroy();
467
+    }
468
+
469
+    @Test
470
+    public void destroy_destroyOverlayManager() {
471
+        uut.setRoot(parentController, new MockPromise());
472
+        activityController.destroy();
473
+        verify(overlayManager, times(1)).destroy();
474
+    }
475
+
476
+    @Test
477
+    public void reload_navigatorIsDestroyedOnReload() {
478
+        uut.setRoot(parentController, new MockPromise());
479
+        uut.onReload();
480
+        verify(parentController, times(1)).destroy();
481
+        verify(overlayManager, times(1)).destroy();
482
+    }
450
 }
483
 }