diff --git a/ChangeLog.md b/ChangeLog.md index b48915c..d1a987c 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,3 +1,7 @@ +Version:1.6.0 +* Add BaseManagerImpl. Logic and data shared by multiple controllers can be put into managers and injected into controllers. +* Delegate fragment's onViewReady lifecycle will be called after state of all controllers are restored if activity is killed by OS + Version:1.5.3 * MvcGraph able to inject concrete class with a public constructor * Fix bug that sub fragments' controller do not restore state diff --git a/build.gradle b/build.gradle index a501e40..b5e2b9a 100644 --- a/build.gradle +++ b/build.gradle @@ -73,8 +73,8 @@ ext { gitUrl = 'https://github.com/kejunxia/AndroidMvc.git' // Git repository URL version = [ major: 1, - minor: 5, - patch : 3 + minor: 6, + patch : 0 ] libGroup = 'com.shipdream' libVersion = "${version.major}.${version.minor}.${version.patch}" diff --git a/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/controller/internal/BaseControllerImpl.java b/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/controller/internal/BaseControllerImpl.java index 73fa61f..95b68fb 100644 --- a/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/controller/internal/BaseControllerImpl.java +++ b/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/controller/internal/BaseControllerImpl.java @@ -75,13 +75,14 @@ public void onConstruct() { } private MODEL createModelInstance() { - if (getModelClassType() == null) { + Class type = getStateType(); + if (type == null) { return null; } else { try { - return new ReflectUtils.newObjectByType<>(getModelClassType()).newInstance(); + return new ReflectUtils.newObjectByType<>(type).newInstance(); } catch (Exception e) { - throw new RuntimeException("Fail to instantiate model by its default constructor"); + throw new RuntimeException("Fail to instantiate state by its default constructor"); } } } @@ -97,10 +98,9 @@ public void onDisposed() { } /** + * Model represents the state of view that this controller is managing. * @return @return Null if the controller doesn't need to get its state saved and restored - * automatically when {@link #getModelClassType()} returns null. e.g. The controller - * always loads resource from remote services so that its state can be thought persisted by the - * remote services. Otherwise returns the model of the controller + * automatically when {@link #getModelClassType()} returns null. Otherwise the model. */ @Override public MODEL getModel() { @@ -112,8 +112,7 @@ public MODEL getModel() { * which is also the model the controller. * * @return Null if the controller doesn't need to get its state saved and restored - * automatically. e.g. The controller always loads resource from remote services so that - * its state can be thought persisted by the remote services. Otherwise the model of the controller + * automatically. Otherwise same as {@link #getModel()} */ @Override final public MODEL getState() { diff --git a/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/event/bus/internal/EventBusImpl.java b/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/event/bus/internal/EventBusImpl.java index cba7e9f..d2b882e 100644 --- a/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/event/bus/internal/EventBusImpl.java +++ b/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/event/bus/internal/EventBusImpl.java @@ -109,8 +109,12 @@ public void post(Object event) { } catch (IllegalAccessException e) { logger.warn(e.getMessage(), e); } catch (InvocationTargetException e) { + String msg = e.getMessage(); + if (msg == null || msg.isEmpty() && e.getCause() != null) { + msg = e.getCause().getMessage(); + } throw new RuntimeException("Not able to post event - " - + event.getClass().getName() + " due to error: " + e.getMessage(), e); + + event.getClass().getName() + " due to error: " + msg, e.getCause()); } } } diff --git a/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/manager/BaseManagerImpl.java b/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/manager/BaseManagerImpl.java new file mode 100644 index 0000000..aece31f --- /dev/null +++ b/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/manager/BaseManagerImpl.java @@ -0,0 +1,106 @@ +package com.shipdream.lib.android.mvc.manager; + +import com.shipdream.lib.android.mvc.Constructable; +import com.shipdream.lib.android.mvc.Disposable; +import com.shipdream.lib.android.mvc.StateKeeper; +import com.shipdream.lib.android.mvc.StateManaged; +import com.shipdream.lib.poke.util.ReflectUtils; + +/** + * Abstract manager with state that needs to be managed. A stateful manager can be shared by multiple + * controllers. For example, LoginManager is an good example that will manage the state of logged in + * user. The log in user object usually is a part of the state to remember the logged in user. + * + *

+ * Managers should only be serving controllers and not visible to views. + *

+ */ +public abstract class BaseManagerImpl implements StateManaged, + Constructable, Disposable { + private STATE state; + + /** + * Bind state to this manager. + * @param state non-null state + * @throws IllegalArgumentException thrown when null is being bound + */ + public void bindState(STATE state) { + if (state == null) { + throw new IllegalArgumentException("Can't bind a null state to a manage explicitly."); + } + this.state = state; + } + + /** + * Called when the manager is injected for the first time or restored when a new instance of + * this manager needs to be instantiated. + * + *

The model of the manager will be instantiated by model's default no-argument constructor. + * However, if the manager needs to be restored, a new instance of state restored by + * {@link #restoreState(Object)} will replace the state created by this method.

+ */ + public void onConstruct() { + state = createModelInstance(); + } + + private STATE createModelInstance() { + Class type = getStateType(); + if (type == null) { + return null; + } else { + try { + return new ReflectUtils.newObjectByType<>(type).newInstance(); + } catch (Exception e) { + throw new RuntimeException("Fail to instantiate state by its default constructor"); + } + } + } + + /** + * Called when the manager is disposed. This occurs when the manager is de-referenced and + * not retained by any other objects. + */ + @Override + public void onDisposed() { + } + + /** + * @return Null if the manager doesn't need to get its state saved and restored automatically. + */ + @Override + final public STATE getState() { + return state; + } + + /** + * @return The class type of the state of the controller that will be used by this manager to + * instantiate its state in {@link #onConstruct()} + */ + @Override + abstract public Class getStateType(); + + /** + * Restore the state of the manager. + *

+ * Note that if the manager doesn't need its state saved and restored automatically and return + * null in {@link #getStateType()}, then this method will have no effect. + *

+ * + * @param restoredState The restored state by {@link StateKeeper} that will be bound to the + * manager when the views of app are restored. + */ + @Override + final public void restoreState(STATE restoredState) { + if (getStateType() != null) { + bindState(restoredState); + } + onRestored(); + } + + /** + * Called when the manager is restored after {@link #restoreState(Object)} is called. + */ + public void onRestored() { + } + +} diff --git a/library/android-mvc-controller/src/test/java/com/shipdream/lib/android/mvc/manager/TestStatefulManager.java b/library/android-mvc-controller/src/test/java/com/shipdream/lib/android/mvc/manager/TestStatefulManager.java new file mode 100644 index 0000000..3816e5e --- /dev/null +++ b/library/android-mvc-controller/src/test/java/com/shipdream/lib/android/mvc/manager/TestStatefulManager.java @@ -0,0 +1,144 @@ +package com.shipdream.lib.android.mvc.manager; + +import org.junit.Assert; +import org.junit.Test; + +public class TestStatefulManager { + @Test(expected = IllegalArgumentException.class) + public void should_throw_exception_when_bind_null_to_stateful_manager() { + BaseManagerImpl manager = new BaseManagerImpl() { + @Override + public Class getStateType() { + return String.class; + } + }; + + manager.bindState(null); + } + + @Test + public void should_rebind_state_after_restoring_manager() { + BaseManagerImpl manager = new BaseManagerImpl() { + + @Override + public Class getStateType() { + return String.class; + } + }; + + Assert.assertNull(manager.getState()); + + manager.restoreState("A"); + + Assert.assertEquals("A", manager.getState()); + } + + @Test + public void should_call_on_restore_call_back_after_manager_is_restored() { + class MyManager extends BaseManagerImpl { + private boolean called = false; + + @Override + public Class getStateType() { + return String.class; + } + + @Override + public void onRestored() { + super.onRestored(); + called = true; + } + }; + + MyManager manager = new MyManager(); + + Assert.assertFalse(manager.called); + + manager.restoreState("A"); + + Assert.assertTrue(manager.called); + } + + public void should_create_state_instance_on_construct_when_the_state_type_is_specified_for_a_stateful_manager() { + class MyManager extends BaseManagerImpl { + @Override + public Class getStateType() { + return String.class; + } + }; + MyManager manager = new MyManager(); + + Assert.assertNull(manager.getState()); + + manager.onConstruct(); + + Assert.assertNotNull(manager.getState()); + } + + public void should_NOT_create_state_instance_on_construct_when_the_state_type_is_null_for_a_stateful_manager() { + class MyManager extends BaseManagerImpl { + @Override + public Class getStateType() { + return null; + } + }; + MyManager manager = new MyManager(); + + Assert.assertNull(manager.getState()); + + manager.onConstruct(); + + Assert.assertNull(manager.getState()); + } + + @Test(expected = RuntimeException.class) + public void should_throw_excpetion_out_when_creating_state_failed() { + class BadClass { + {int x = 1 / 0;} + } + + class MyManager extends BaseManagerImpl { + @Override + public Class getStateType() { + return BadClass.class; + } + }; + + MyManager manager = new MyManager(); + + manager.onConstruct(); + } + + @Test(expected = IllegalArgumentException.class) + public void should_throw_excpetion_when_binding_null_to_stateful_manager() { + class MyManager extends BaseManagerImpl { + @Override + public Class getStateType() { + return String.class; + } + }; + + MyManager manager = new MyManager(); + + manager.bindState(null); + } + + @Test + public void should_be_able_to_successfully_bind_state_to_stateful_manager() { + class MyManager extends BaseManagerImpl { + @Override + public Class getStateType() { + return String.class; + } + }; + + MyManager manager = new MyManager(); + + Assert.assertNotEquals("B", manager.getState()); + + manager.bindState("B"); + + Assert.assertEquals("B", manager.getState()); + } + +} diff --git a/library/android-mvc-test/src/androidTest/java/com/shipdream/lib/android/mvc/view/injection/TestInjectedStateManagedObjects.java b/library/android-mvc-test/src/androidTest/java/com/shipdream/lib/android/mvc/view/injection/TestInjectedStateManagedObjects.java index 4ed1c04..9b60805 100644 --- a/library/android-mvc-test/src/androidTest/java/com/shipdream/lib/android/mvc/view/injection/TestInjectedStateManagedObjects.java +++ b/library/android-mvc-test/src/androidTest/java/com/shipdream/lib/android/mvc/view/injection/TestInjectedStateManagedObjects.java @@ -19,7 +19,6 @@ import android.util.Log; import com.shipdream.lib.android.mvc.view.BaseTestCase; -import com.shipdream.lib.android.mvc.view.nav.MvcTestActivityNavigation; import com.shipdream.lib.android.mvc.view.test.R; import org.junit.Test; @@ -30,10 +29,10 @@ import static android.support.test.espresso.matcher.ViewMatchers.withId; import static android.support.test.espresso.matcher.ViewMatchers.withText; -public class TestInjectedStateManagedObjects extends BaseTestCase { +public class TestInjectedStateManagedObjects extends BaseTestCase { public TestInjectedStateManagedObjects() { - super(InjectionTestActivity.class); + super(InjectionTestActivityStateManagedObjects.class); } @Override @@ -43,15 +42,12 @@ public void tearDown() throws Exception { } @Test - public void should_manage_state_of_nested_stateManagedObjects() throws Throwable { + public void test_should_manage_state_of_nested_stateManagedObjects() throws Throwable { if (!isDontKeepActivities()) { Log.i(getClass().getSimpleName(), "testLifeCyclesWhenKeepActivities not tested as Don't Keep Activities setting is disabled"); return; } - navigationController.navigate(this).to(MvcTestActivityNavigation.Loc.D); - waitTest(); - onView(withId(R.id.textA)).check(matches(withText(""))); onView(withId(R.id.fragment_injection_root)).perform(click()); @@ -63,10 +59,10 @@ public void should_manage_state_of_nested_stateManagedObjects() throws Throwable onView(withId(R.id.textA)).check(matches(withText("2:B"))); pressHome(); - waitTest(2000); + waitTest(1000); bringBack(); - waitTest(2000); + waitTest(1000); onView(withId(R.id.fragment_injection_root)).perform(click()); onView(withId(R.id.textA)).check(matches(withText("3:C"))); diff --git a/library/android-mvc-test/src/androidTest/java/com/shipdream/lib/android/mvc/view/injection/TestInjectionAndLifeCycleForRootFragment.java b/library/android-mvc-test/src/androidTest/java/com/shipdream/lib/android/mvc/view/injection/TestInjectionAndLifeCycleForRootFragment.java new file mode 100644 index 0000000..800b3e4 --- /dev/null +++ b/library/android-mvc-test/src/androidTest/java/com/shipdream/lib/android/mvc/view/injection/TestInjectionAndLifeCycleForRootFragment.java @@ -0,0 +1,69 @@ +/* + * Copyright 2015 Kejun Xia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.shipdream.lib.android.mvc.view.injection; + +import android.util.Log; + +import com.shipdream.lib.android.mvc.view.BaseTestCase; +import com.shipdream.lib.android.mvc.view.test.R; + +import org.junit.Test; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static android.support.test.espresso.matcher.ViewMatchers.withText; + +public class TestInjectionAndLifeCycleForRootFragment extends BaseTestCase { + + @Override + protected void waitTest() throws InterruptedException { + waitTest(1000); + } + + public TestInjectionAndLifeCycleForRootFragment() { + super(InjectionTestActivityTestRootFragment.class); + } + + @Override + public void tearDown() throws Exception { + super.tearDown(); + waitTest(); + } + + @Test + public void test_should_delay_call_on_view_ready_on_root_fragment_after_dependencies_injected_when_restore_from_kill() throws Throwable { + if (!isDontKeepActivities()) { + Log.i(getClass().getSimpleName(), "Not tested as Don't Keep Activities setting is disabled"); + return; + } + + //=============================> At A + onView(withId(R.id.textA)).check(matches(withText("Added by FragmentA"))); + onView(withId(R.id.textB)).check(matches(withText("Added by FragmentA"))); + onView(withId(R.id.textC)).check(matches(withText(""))); + + pressHome(); + waitTest(); + + bringBack(); + waitTest(); + onView(withId(R.id.textA)).check(matches(withText("Added by FragmentA\nOK\nAdded by FragmentA"))); + onView(withId(R.id.textB)).check(matches(withText("Added by FragmentA\nAdded by FragmentA"))); + } + +} diff --git a/library/android-mvc-test/src/androidTest/java/com/shipdream/lib/android/mvc/view/viewpager/TestFragmentsInViewPager.java b/library/android-mvc-test/src/androidTest/java/com/shipdream/lib/android/mvc/view/viewpager/TestFragmentsInViewPager.java index 7fa268d..47ea1a5 100644 --- a/library/android-mvc-test/src/androidTest/java/com/shipdream/lib/android/mvc/view/viewpager/TestFragmentsInViewPager.java +++ b/library/android-mvc-test/src/androidTest/java/com/shipdream/lib/android/mvc/view/viewpager/TestFragmentsInViewPager.java @@ -156,7 +156,7 @@ public void test_should_call_onViewReady_in_tab_fragments_when_restored_hosting_ lifeCycleValidatorC.expect(); //=============================> At Sub Fragment - navigationController.navigateTo(this, SubFragment.class.getSimpleName()); + navigationController.navigate(this).to(SubFragment.class.getSimpleName()); waitTest(1200); lifeCycleValidator.expect(LifeCycle.onPushingToBackStack, LifeCycle.onDestroyView); @@ -183,8 +183,8 @@ public void test_should_call_onViewReady_in_tab_fragments_when_restored_hosting_ lifeCycleValidatorC.expect(); - //=============================> At A - navigationController.navigateBack(this); + //=============================> Back to home + navigationController.navigate(this).back(); waitTest(1200); lifeCycleValidator.expect( @@ -212,6 +212,10 @@ public void test_should_call_onViewReady_in_tab_fragments_when_restored_hosting_ LifeCycle.onPoppedOutToFront); lifeCycleValidatorC.expect(); + + navigationController.navigate(this).back(null); + navigationController.navigate(this).back(); + waitTest(1000); } @Test diff --git a/library/android-mvc-test/src/main/AndroidManifest.xml b/library/android-mvc-test/src/main/AndroidManifest.xml index ae10a4d..ac2e652 100644 --- a/library/android-mvc-test/src/main/AndroidManifest.xml +++ b/library/android-mvc-test/src/main/AndroidManifest.xml @@ -50,6 +50,12 @@ android:theme="@style/Theme.AppCompat.Light.NoActionBar"> + + + + diff --git a/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/injection/InjectionTestActivityStateManagedObjects.java b/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/injection/InjectionTestActivityStateManagedObjects.java new file mode 100644 index 0000000..65368fa --- /dev/null +++ b/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/injection/InjectionTestActivityStateManagedObjects.java @@ -0,0 +1,52 @@ +/* + * Copyright 2015 Kejun Xia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.shipdream.lib.android.mvc.view.injection; + +import com.shipdream.lib.android.mvc.controller.NavigationController; +import com.shipdream.lib.android.mvc.view.MvcActivity; +import com.shipdream.lib.android.mvc.view.MvcFragment; +import com.shipdream.lib.android.mvc.view.nav.MvcTestActivityNavigation; + +import javax.inject.Inject; + +public class InjectionTestActivityStateManagedObjects extends MvcActivity { + @Override + protected Class mapNavigationFragment(String locationId) { + switch (locationId) { + case MvcTestActivityNavigation.Loc.D: + return FragmentD.class; + default: + return null; + } + } + + @Override + protected Class getDelegateFragmentClass() { + return HomeFragment.class; + } + + public static class HomeFragment extends DelegateFragment { + @Inject + private NavigationController navigationController; + + @Override + protected void onStartUp() { + navigationController.navigate(this).to(MvcTestActivityNavigation.Loc.D, null); + } + } + +} diff --git a/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/injection/InjectionTestActivityTestRootFragment.java b/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/injection/InjectionTestActivityTestRootFragment.java new file mode 100644 index 0000000..8af2458 --- /dev/null +++ b/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/injection/InjectionTestActivityTestRootFragment.java @@ -0,0 +1,77 @@ +/* + * Copyright 2015 Kejun Xia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.shipdream.lib.android.mvc.view.injection; + +import android.os.Bundle; +import android.view.View; + +import com.shipdream.lib.android.mvc.controller.NavigationController; +import com.shipdream.lib.android.mvc.view.MvcActivity; +import com.shipdream.lib.android.mvc.view.MvcFragment; +import com.shipdream.lib.android.mvc.view.injection.controller.ControllerA; +import com.shipdream.lib.android.mvc.view.nav.MvcTestActivityNavigation; + +import javax.inject.Inject; + +public class InjectionTestActivityTestRootFragment extends MvcActivity { + @Override + protected Class mapNavigationFragment(String locationId) { + switch (locationId) { + case MvcTestActivityNavigation.Loc.A: + return FragmentA.class; + default: + return null; + } + } + + @Override + protected Class getDelegateFragmentClass() { + return HomeFragment.class; + } + + public static class HomeFragment extends DelegateFragment { + @Inject + private NavigationController navigationController; + + @Inject + private ControllerA controllerA; + + @Override + protected void onStartUp() { + navigationController.navigate(this).to(MvcTestActivityNavigation.Loc.A, null); + } + + @Override + public void onViewReady(View view, Bundle savedInstanceState, Reason reason) { + super.onViewReady(view, savedInstanceState, reason); + + if (savedInstanceState != null) { + controllerA.addTag("OK"); + } + } + + @Override + public void onViewStateRestored(Bundle savedInstanceState) { + super.onViewStateRestored(savedInstanceState); + + if (savedInstanceState != null) { + System.out.print(""); + } + } + } + +} diff --git a/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/injection/manager/internal/AccountManagerImpl.java b/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/injection/manager/internal/AccountManagerImpl.java index 98821fe..eeff482 100644 --- a/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/injection/manager/internal/AccountManagerImpl.java +++ b/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/injection/manager/internal/AccountManagerImpl.java @@ -1,21 +1,20 @@ package com.shipdream.lib.android.mvc.view.injection.manager.internal; -import com.shipdream.lib.android.mvc.Constructable; -import com.shipdream.lib.android.mvc.StateManaged; +import com.shipdream.lib.android.mvc.manager.BaseManagerImpl; import com.shipdream.lib.android.mvc.view.injection.manager.AccountManager; import com.shipdream.lib.android.mvc.view.injection.service.StorageService; import javax.inject.Inject; -public class AccountManagerImpl implements AccountManager, StateManaged, Constructable { - private Session session; +public class AccountManagerImpl extends BaseManagerImpl + implements AccountManager { @Inject private StorageService storageService; @Override public void setUserId(long id) { - session.setUserId(id); + getState().setUserId(id); } @Override @@ -33,23 +32,8 @@ public void setContent(String content) { storageService.setContent(content); } - @Override - public void onConstruct() { - session = new Session(); - } - @Override public Class getStateType() { return Session.class; } - - @Override - public Session getState() { - return session; - } - - @Override - public void restoreState(Session restoredState) { - this.session = restoredState; - } } diff --git a/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/viewpager/BaseTabFragment.java b/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/viewpager/BaseTabFragment.java index 228f95b..ed6122b 100644 --- a/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/viewpager/BaseTabFragment.java +++ b/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/viewpager/BaseTabFragment.java @@ -8,7 +8,7 @@ public abstract class BaseTabFragment extends MvcFragment { protected abstract LifeCycleMonitor getLifeCycleMonitor(); - + @Override public void onViewReady(View view, Bundle savedInstanceState, MvcFragment.Reason reason) { getLifeCycleMonitor().onCreateView(view, savedInstanceState); diff --git a/library/android-mvc-test/src/main/res/layout/fragment_view_pager_home.xml b/library/android-mvc-test/src/main/res/layout/fragment_view_pager_home.xml index 9bb020c..d0dd5bd 100644 --- a/library/android-mvc-test/src/main/res/layout/fragment_view_pager_home.xml +++ b/library/android-mvc-test/src/main/res/layout/fragment_view_pager_home.xml @@ -20,6 +20,13 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> + + +