From ae90c0f3495262122c862db818ab92cb5dc29804 Mon Sep 17 00:00:00 2001 From: Kejun Xia Date: Tue, 20 Oct 2015 23:25:26 +1100 Subject: [PATCH 01/28] Decouple EventBusC2V from AndroidMvc --- .../shipdream/lib/android/mvc/Injector.java | 19 ++++++++++++++ .../lib/android/mvc/view/AndroidMvc.java | 20 --------------- .../lib/android/mvc/view/EventRegister.java | 25 +++++++++++++++++-- .../lib/android/mvc/view/MvcService.java | 2 +- 4 files changed, 43 insertions(+), 23 deletions(-) create mode 100644 library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/Injector.java diff --git a/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/Injector.java b/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/Injector.java new file mode 100644 index 0000000..a272cae --- /dev/null +++ b/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/Injector.java @@ -0,0 +1,19 @@ +package com.shipdream.lib.android.mvc; + +import com.shipdream.lib.poke.exception.PokeException; + +public class Injector { + private static MvcGraph mvcGraph; + + public static void configGraph(MvcGraph.BaseDependencies baseDependencies) { + try { + mvcGraph = new MvcGraph(baseDependencies); + } catch (PokeException e) { + throw new RuntimeException(e); + } + } + + public static MvcGraph getGraph() { + return mvcGraph; + } +} diff --git a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/AndroidMvc.java b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/AndroidMvc.java index db1033e..da3a3a7 100644 --- a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/AndroidMvc.java +++ b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/AndroidMvc.java @@ -31,7 +31,6 @@ import com.shipdream.lib.android.mvc.controller.internal.AndroidPosterImpl; import com.shipdream.lib.android.mvc.event.BaseEventV2V; import com.shipdream.lib.android.mvc.event.bus.EventBus; -import com.shipdream.lib.android.mvc.event.bus.annotation.EventBusC2V; import com.shipdream.lib.android.mvc.event.bus.internal.EventBusImpl; import com.shipdream.lib.poke.exception.PokeException; @@ -43,8 +42,6 @@ import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; -import javax.inject.Inject; - import static android.os.Process.THREAD_PRIORITY_BACKGROUND; /** @@ -54,16 +51,9 @@ * {@link MvcGraph} how it works. */ public class AndroidMvc { - private static class EventBusC2VHolder { - @Inject - @EventBusC2V - EventBus eventBusC2V; - } - static final String MVC_SATE_PREFIX = "__--AndroidMvc:State:"; static final String FRAGMENT_TAG_PREFIX = "__--AndroidMvc:Fragment:"; private static MvcGraph mvcGraph; - private static EventBusC2VHolder eventBusC2VHolder; private static EventBus eventBusV2V; private static DefaultStateKeeper sStateManager; @@ -96,8 +86,6 @@ public static MvcGraph graph() { public static void configGraph(MvcGraph.BaseDependencies baseDependencies) { try { mvcGraph = new MvcGraph(baseDependencies); - eventBusC2VHolder = new EventBusC2VHolder(); - mvcGraph.inject(eventBusC2VHolder); } catch (PokeException e) { throw new RuntimeException(e); } @@ -151,14 +139,6 @@ static void restoreControllerStateByTheirOwn(Bundle savedState, Object object) { } } - /** - * Gets Controllers to Views event bus. Internal use by AndroidMvc library only. - * @return The event bus - */ - static EventBus getEventBusC2V() { - return eventBusC2VHolder.eventBusC2V; - } - /** * Gets the views to views event bus. By default all {@link MvcFragment}s, * {@link MvcDialogFragment} and {@link MvcService} have registered to this event bus. They diff --git a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/EventRegister.java b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/EventRegister.java index a49f065..286e069 100644 --- a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/EventRegister.java +++ b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/EventRegister.java @@ -16,10 +16,31 @@ package com.shipdream.lib.android.mvc.view; +import com.shipdream.lib.android.mvc.event.bus.EventBus; +import com.shipdream.lib.android.mvc.event.bus.annotation.EventBusC2V; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.inject.Inject; + class EventRegister { + private static class C2VBusHolder { + @Inject + @EventBusC2V + private EventBus eventBusC2V; + + private static C2VBusHolder instance; + + private static C2VBusHolder getInstance() { + if (instance == null) { + instance = new C2VBusHolder(); + AndroidMvc.graph().inject(instance); + } + return instance; + } + } + private Logger logger = LoggerFactory.getLogger(getClass()); private Object androidComponent; private boolean eventsRegistered = false; @@ -33,7 +54,7 @@ public EventRegister(Object androidComponent) { */ public void registerEventBuses() { if (!eventsRegistered) { - AndroidMvc.getEventBusC2V().register(androidComponent); + C2VBusHolder.getInstance().eventBusC2V.register(androidComponent); AndroidMvc.getEventBusV2V().register(androidComponent); eventsRegistered = true; logger.trace("+Event bus registered for view - '{}'.", @@ -49,7 +70,7 @@ public void registerEventBuses() { */ public void unregisterEventBuses() { if (eventsRegistered) { - AndroidMvc.getEventBusC2V().unregister(androidComponent); + C2VBusHolder.getInstance().eventBusC2V.unregister(androidComponent); AndroidMvc.getEventBusV2V().unregister(androidComponent); eventsRegistered = false; logger.trace("-Event bus unregistered for view - '{}' and its controllers.", diff --git a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcService.java b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcService.java index 2a25485..12f0691 100644 --- a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcService.java +++ b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcService.java @@ -55,6 +55,6 @@ public void onDestroy() { * @param event */ protected void postEventV2V(BaseEventV2V event) { - AndroidMvc.getEventBusC2V().post(event); + AndroidMvc.getEventBusV2V().post(event); } } From 16fac5e899b216417dd480b9697191eb33b8cd30 Mon Sep 17 00:00:00 2001 From: Kejun Xia Date: Wed, 21 Oct 2015 23:33:36 +1100 Subject: [PATCH 02/28] Move instance of MvcGraph to controller layer --- .../shipdream/lib/android/mvc/Injector.java | 6 +- .../shipdream/lib/android/mvc/MvcConfig.java | 11 +++ .../lib/android/mvc/view/AndroidMvc.java | 77 ++++++++----------- 3 files changed, 47 insertions(+), 47 deletions(-) create mode 100644 library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/MvcConfig.java diff --git a/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/Injector.java b/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/Injector.java index a272cae..475af72 100644 --- a/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/Injector.java +++ b/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/Injector.java @@ -5,7 +5,7 @@ public class Injector { private static MvcGraph mvcGraph; - public static void configGraph(MvcGraph.BaseDependencies baseDependencies) { + static void configGraph(MvcGraph.BaseDependencies baseDependencies) { try { mvcGraph = new MvcGraph(baseDependencies); } catch (PokeException e) { @@ -13,6 +13,10 @@ public static void configGraph(MvcGraph.BaseDependencies baseDependencies) { } } + /** + * Get the graph managing injectable objects. + * @return + */ public static MvcGraph getGraph() { return mvcGraph; } diff --git a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/MvcConfig.java b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/MvcConfig.java new file mode 100644 index 0000000..78429db --- /dev/null +++ b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/MvcConfig.java @@ -0,0 +1,11 @@ +package com.shipdream.lib.android.mvc; + +public class MvcConfig { + /** + * Config the dependencies of MvcGraph. + * @param dependencies the dependencies. + */ + public static void configGraph(MvcGraph.BaseDependencies dependencies) { + Injector.configGraph(dependencies); + } +} diff --git a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/AndroidMvc.java b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/AndroidMvc.java index da3a3a7..7ba01b5 100644 --- a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/AndroidMvc.java +++ b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/AndroidMvc.java @@ -23,6 +23,8 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonSyntaxException; +import com.shipdream.lib.android.mvc.Injector; +import com.shipdream.lib.android.mvc.MvcConfig; import com.shipdream.lib.android.mvc.MvcGraph; import com.shipdream.lib.android.mvc.StateKeeper; import com.shipdream.lib.android.mvc.StateManaged; @@ -32,7 +34,6 @@ import com.shipdream.lib.android.mvc.event.BaseEventV2V; import com.shipdream.lib.android.mvc.event.bus.EventBus; import com.shipdream.lib.android.mvc.event.bus.internal.EventBusImpl; -import com.shipdream.lib.poke.exception.PokeException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -46,19 +47,42 @@ /** * {@link AndroidMvc} will generate a default {@link MvcGraph} for injection. To replace - * {@link MvcGraph.BaseDependencies} use {@link #configGraph(MvcGraph.BaseDependencies)}. + * {@link MvcGraph.BaseDependencies} use {@link MvcConfig#configGraph(MvcGraph.BaseDependencies)}. * By default, the graph uses naming convention to locate the implementations of dependencies. See * {@link MvcGraph} how it works. */ public class AndroidMvc { static final String MVC_SATE_PREFIX = "__--AndroidMvc:State:"; static final String FRAGMENT_TAG_PREFIX = "__--AndroidMvc:Fragment:"; - private static MvcGraph mvcGraph; private static EventBus eventBusV2V; private static DefaultStateKeeper sStateManager; + private static class DefaultControllerDependencies extends MvcGraph.BaseDependencies { + private static ExecutorService sNetworkExecutorService; + private final static String BACKGROUND_THREAD_NAME = "AndroidMvcDefaultBackgroundThread"; + + @Override + public ExecutorService createExecutorService() { + if (sNetworkExecutorService == null) { + sNetworkExecutorService = Executors.newFixedThreadPool(10, new ThreadFactory() { + @Override + public Thread newThread(final @NonNull Runnable r) { + return new Thread(new Runnable() { + @Override + public void run() { + android.os.Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND); + r.run(); + } + }, BACKGROUND_THREAD_NAME); + } + }); + } + return sNetworkExecutorService; + } + } + static { - configGraph(new DefaultControllerDependencies()); + MvcConfig.configGraph(new DefaultControllerDependencies()); sStateManager = new DefaultStateKeeper(); eventBusV2V = new EventBusImpl(); @@ -73,33 +97,18 @@ private AndroidMvc() { * @return The {@link MvcGraph} */ public static MvcGraph graph() { - return mvcGraph; - } - - /** - * Config the {@link MvcGraph} by custom dependencies. - *

Note that, the graph will be regenerated after config. In addition, it's cached instances - * will be regenerated such as cached singletons.

- * - * @param baseDependencies The dependencies of all controllers - */ - public static void configGraph(MvcGraph.BaseDependencies baseDependencies) { - try { - mvcGraph = new MvcGraph(baseDependencies); - } catch (PokeException e) { - throw new RuntimeException(e); - } + return Injector.getGraph(); } static void saveStateOfAllControllers(Bundle outState) { sStateManager.bundle = outState; - mvcGraph.saveAllStates(sStateManager); + Injector.getGraph().saveAllStates(sStateManager); sStateManager.bundle = null; } static void restoreStateOfAllControllers(Bundle savedState) { sStateManager.bundle = savedState; - mvcGraph.restoreAllStates(sStateManager); + Injector.getGraph().restoreAllStates(sStateManager); sStateManager.bundle = null; } @@ -162,30 +171,6 @@ public static void setCustomStateKeeper(AndroidStateKeeper customStateKeeper) { sStateManager.customStateKeeper = customStateKeeper; } - private static class DefaultControllerDependencies extends MvcGraph.BaseDependencies { - private static ExecutorService sNetworkExecutorService; - private final static String BACKGROUND_THREAD_NAME = "AndroidMvcDefaultBackgroundThread"; - - @Override - public ExecutorService createExecutorService() { - if (sNetworkExecutorService == null) { - sNetworkExecutorService = Executors.newFixedThreadPool(10, new ThreadFactory() { - @Override - public Thread newThread(final @NonNull Runnable r) { - return new Thread(new Runnable() { - @Override - public void run() { - android.os.Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND); - r.run(); - } - }, BACKGROUND_THREAD_NAME); - } - }); - } - return sNetworkExecutorService; - } - } - private static class DefaultStateKeeper implements StateKeeper { private static Gson gson; private Bundle bundle; From fc4ee5c3d640d5747ca917767248f6c80e9d5b6c Mon Sep 17 00:00:00 2001 From: Kejun Xia Date: Thu, 22 Oct 2015 23:39:00 +1100 Subject: [PATCH 03/28] EventBusV2V is injectable now --- .../shipdream/lib/android/mvc/Injector.java | 9 +++-- .../shipdream/lib/android/mvc/MvcConfig.java | 11 ------- .../lib/android/mvc/view/AndroidMvc.java | 33 +++++++++---------- .../lib/android/mvc/view/EventBusV2V.java | 17 ++++++++++ .../lib/android/mvc/view/EventRegister.java | 24 +++++++++----- .../android/mvc/view/MvcDialogFragment.java | 14 ++++++-- .../lib/android/mvc/view/MvcFragment.java | 14 ++++++-- .../lib/android/mvc/view/MvcService.java | 12 +++++-- 8 files changed, 88 insertions(+), 46 deletions(-) delete mode 100644 library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/MvcConfig.java create mode 100644 library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/EventBusV2V.java diff --git a/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/Injector.java b/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/Injector.java index 475af72..615d592 100644 --- a/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/Injector.java +++ b/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/Injector.java @@ -5,9 +5,14 @@ public class Injector { private static MvcGraph mvcGraph; - static void configGraph(MvcGraph.BaseDependencies baseDependencies) { + /** + * Config the dependencies of MvcGraph. Be careful to use this method because it will dump the + * existing graph and all injectable instances managed by it + * @param dependencies the dependencies. + */ + public static void configGraph(MvcGraph.BaseDependencies dependencies) { try { - mvcGraph = new MvcGraph(baseDependencies); + mvcGraph = new MvcGraph(dependencies); } catch (PokeException e) { throw new RuntimeException(e); } diff --git a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/MvcConfig.java b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/MvcConfig.java deleted file mode 100644 index 78429db..0000000 --- a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/MvcConfig.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.shipdream.lib.android.mvc; - -public class MvcConfig { - /** - * Config the dependencies of MvcGraph. - * @param dependencies the dependencies. - */ - public static void configGraph(MvcGraph.BaseDependencies dependencies) { - Injector.configGraph(dependencies); - } -} diff --git a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/AndroidMvc.java b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/AndroidMvc.java index 7ba01b5..1f87e9e 100644 --- a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/AndroidMvc.java +++ b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/AndroidMvc.java @@ -24,16 +24,16 @@ import com.google.gson.GsonBuilder; import com.google.gson.JsonSyntaxException; import com.shipdream.lib.android.mvc.Injector; -import com.shipdream.lib.android.mvc.MvcConfig; import com.shipdream.lib.android.mvc.MvcGraph; import com.shipdream.lib.android.mvc.StateKeeper; import com.shipdream.lib.android.mvc.StateManaged; import com.shipdream.lib.android.mvc.controller.BaseController; import com.shipdream.lib.android.mvc.controller.NavigationController; import com.shipdream.lib.android.mvc.controller.internal.AndroidPosterImpl; -import com.shipdream.lib.android.mvc.event.BaseEventV2V; import com.shipdream.lib.android.mvc.event.bus.EventBus; import com.shipdream.lib.android.mvc.event.bus.internal.EventBusImpl; +import com.shipdream.lib.poke.Component; +import com.shipdream.lib.poke.Provides; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,18 +43,19 @@ import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; +import javax.inject.Singleton; + import static android.os.Process.THREAD_PRIORITY_BACKGROUND; /** * {@link AndroidMvc} will generate a default {@link MvcGraph} for injection. To replace - * {@link MvcGraph.BaseDependencies} use {@link MvcConfig#configGraph(MvcGraph.BaseDependencies)}. + * {@link MvcGraph.BaseDependencies} use {@link Injector#configGraph(MvcGraph.BaseDependencies)}. * By default, the graph uses naming convention to locate the implementations of dependencies. See * {@link MvcGraph} how it works. */ public class AndroidMvc { static final String MVC_SATE_PREFIX = "__--AndroidMvc:State:"; static final String FRAGMENT_TAG_PREFIX = "__--AndroidMvc:Fragment:"; - private static EventBus eventBusV2V; private static DefaultStateKeeper sStateManager; private static class DefaultControllerDependencies extends MvcGraph.BaseDependencies { @@ -81,10 +82,19 @@ public void run() { } } + static class ViewComponent extends Component { + @Provides + @EventBusV2V + @Singleton + public EventBus providesIEventBusC2V() { + return new EventBusImpl(); + } + } + static { - MvcConfig.configGraph(new DefaultControllerDependencies()); + Injector.configGraph(new DefaultControllerDependencies()); + Injector.getGraph().register(new ViewComponent()); sStateManager = new DefaultStateKeeper(); - eventBusV2V = new EventBusImpl(); AndroidPosterImpl.init(); } @@ -148,17 +158,6 @@ static void restoreControllerStateByTheirOwn(Bundle savedState, Object object) { } } - /** - * Gets the views to views event bus. By default all {@link MvcFragment}s, - * {@link MvcDialogFragment} and {@link MvcService} have registered to this event bus. They - * also have short cut methods to post {@link BaseEventV2V}. Custom views which need to use the - * event bus must register to this event respectively.. - * @return The event bus - */ - public static EventBus getEventBusV2V() { - return eventBusV2V; - } - /** * Set the custom state keeper for the objects that are wanted to be saved and restored by it. * Other objects will still be saved and restored by json serialization. diff --git a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/EventBusV2V.java b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/EventBusV2V.java new file mode 100644 index 0000000..d3bcb55 --- /dev/null +++ b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/EventBusV2V.java @@ -0,0 +1,17 @@ +package com.shipdream.lib.android.mvc.view; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import javax.inject.Qualifier; + +/** + * Indicates the annotated event bus is for communication among views. Events through the + * event bus annotated by this annotation should be posted and received on UI thread. + */ +@Qualifier +@Documented +@Retention(RetentionPolicy.RUNTIME) +public @interface EventBusV2V { +} diff --git a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/EventRegister.java b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/EventRegister.java index 286e069..dad1169 100644 --- a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/EventRegister.java +++ b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/EventRegister.java @@ -16,6 +16,7 @@ package com.shipdream.lib.android.mvc.view; +import com.shipdream.lib.android.mvc.event.BaseEventV2V; import com.shipdream.lib.android.mvc.event.bus.EventBus; import com.shipdream.lib.android.mvc.event.bus.annotation.EventBusC2V; @@ -25,16 +26,20 @@ import javax.inject.Inject; class EventRegister { - private static class C2VBusHolder { + private static class BusHolder { @Inject @EventBusC2V private EventBus eventBusC2V; - private static C2VBusHolder instance; + @Inject + @EventBusV2V + private EventBus eventBusV2V; + + private static BusHolder instance; - private static C2VBusHolder getInstance() { + private static BusHolder getInstance() { if (instance == null) { - instance = new C2VBusHolder(); + instance = new BusHolder(); AndroidMvc.graph().inject(instance); } return instance; @@ -54,8 +59,8 @@ public EventRegister(Object androidComponent) { */ public void registerEventBuses() { if (!eventsRegistered) { - C2VBusHolder.getInstance().eventBusC2V.register(androidComponent); - AndroidMvc.getEventBusV2V().register(androidComponent); + BusHolder.getInstance().eventBusC2V.register(androidComponent); + BusHolder.getInstance().eventBusV2V.register(androidComponent); eventsRegistered = true; logger.trace("+Event bus registered for view - '{}'.", androidComponent.getClass().getSimpleName()); @@ -70,8 +75,8 @@ public void registerEventBuses() { */ public void unregisterEventBuses() { if (eventsRegistered) { - C2VBusHolder.getInstance().eventBusC2V.unregister(androidComponent); - AndroidMvc.getEventBusV2V().unregister(androidComponent); + BusHolder.getInstance().eventBusC2V.unregister(androidComponent); + BusHolder.getInstance().eventBusV2V.unregister(androidComponent); eventsRegistered = false; logger.trace("-Event bus unregistered for view - '{}' and its controllers.", androidComponent.getClass().getSimpleName()); @@ -81,4 +86,7 @@ public void unregisterEventBuses() { } } + void postEventV2V(BaseEventV2V event) { + BusHolder.getInstance().eventBusV2V.post(event); + } } diff --git a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcDialogFragment.java b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcDialogFragment.java index 363c15b..4c56425 100644 --- a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcDialogFragment.java +++ b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcDialogFragment.java @@ -66,11 +66,19 @@ public void onDestroy() { } /** - * Post an event from this view to other views - * @param event The event + * Post an event from this view to other views. Using EventBusV2V is a handy way to + * inter-communicate among views but it's a little anti pattern. Best practice is that views + * communicates to other views through controllers and EventBusC2V. For example, if view1 wants + * to talk to view2, instead of sending V2V events, view1 can send a command to a controller and + * that controller will fire an C2VEvent that will be received by view2. In this way, more + * business logic can be wrapped into controllers rather than exposed to view1. + * + *

However, it's not absolute. If touching a controller is an overkill, sending events + * directly through V2V channel is still an option.

+ * @param event */ protected void postEventV2V(BaseEventV2V event) { - AndroidMvc.getEventBusV2V().post(event); + eventRegister.postEventV2V(event); } } diff --git a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcFragment.java b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcFragment.java index 2a75b73..bfb1ddd 100644 --- a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcFragment.java +++ b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcFragment.java @@ -471,10 +471,18 @@ public boolean onBackButtonPressed() { } /** - * Post an event from this view to other views - * @param event The view to view event + * Post an event from this view to other views. Using EventBusV2V is a handy way to + * inter-communicate among views but it's a little anti pattern. Best practice is that views + * communicates to other views through controllers and EventBusC2V. For example, if view1 wants + * to talk to view2, instead of sending V2V events, view1 can send a command to a controller and + * that controller will fire an C2VEvent that will be received by view2. In this way, more + * business logic can be wrapped into controllers rather than exposed to view1. + * + *

However, it's not absolute. If touching a controller is an overkill, sending events + * directly through V2V channel is still an option.

+ * @param event */ protected void postEventV2V(BaseEventV2V event) { - AndroidMvc.getEventBusV2V().post(event); + eventRegister.postEventV2V(event); } } diff --git a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcService.java b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcService.java index 12f0691..5375a01 100644 --- a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcService.java +++ b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcService.java @@ -51,10 +51,18 @@ public void onDestroy() { } /** - * Post an event from this view to other views + * Post an event from this view to other views. Using EventBusV2V is a handy way to + * inter-communicate among views but it's a little anti pattern. Best practice is that views + * communicates to other views through controllers and EventBusC2V. For example, if view1 wants + * to talk to view2, instead of sending V2V events, view1 can send a command to a controller and + * that controller will fire an C2VEvent that will be received by view2. In this way, more + * business logic can be wrapped into controllers rather than exposed to view1. + * + *

However, it's not absolute. If touching a controller is an overkill, sending events + * directly through V2V channel is still an option.

* @param event */ protected void postEventV2V(BaseEventV2V event) { - AndroidMvc.getEventBusV2V().post(event); + eventRegister.postEventV2V(event); } } From dfbae49929a26d493d97b5f738ba47d379096e18 Mon Sep 17 00:00:00 2001 From: Kejun Xia Date: Wed, 21 Oct 2015 16:55:25 +1100 Subject: [PATCH 04/28] Refactor how V2V event bus is injected and add tests for it --- .../mvc/view/eventv2v/TestV2VEvents.java | 73 +++++++++++++++++++ .../src/main/AndroidManifest.xml | 6 ++ .../view/eventv2v/EventBusV2VActivity.java | 63 ++++++++++++++++ .../eventv2v/EventBusV2VDialogFragment.java | 50 +++++++++++++ .../view/eventv2v/EventBusV2VFragment.java | 71 ++++++++++++++++++ .../mvc/view/eventv2v/EventBusV2VService.java | 36 +++++++++ .../lib/android/mvc/view/eventv2v/Events.java | 30 ++++++++ .../controller/V2VTestController.java | 23 ++++++ .../internal/V2VTestControllerImpl.java | 16 ++++ .../src/main/res/layout/fragment_mvc_v2v.xml | 48 ++++++++++++ .../res/layout/fragment_mvc_v2v_dialog.xml | 42 +++++++++++ .../lib/android/mvc/view/EventRegister.java | 60 +++++++-------- .../android/mvc/view/MvcDialogFragment.java | 10 +++ .../lib/android/mvc/view/MvcFragment.java | 7 +- .../lib/android/mvc/view/MvcService.java | 2 + 15 files changed, 503 insertions(+), 34 deletions(-) create mode 100644 library/android-mvc-test/src/androidTest/java/com/shipdream/lib/android/mvc/view/eventv2v/TestV2VEvents.java create mode 100644 library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/EventBusV2VActivity.java create mode 100644 library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/EventBusV2VDialogFragment.java create mode 100644 library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/EventBusV2VFragment.java create mode 100644 library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/EventBusV2VService.java create mode 100644 library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/Events.java create mode 100644 library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/controller/V2VTestController.java create mode 100644 library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/controller/internal/V2VTestControllerImpl.java create mode 100644 library/android-mvc-test/src/main/res/layout/fragment_mvc_v2v.xml create mode 100644 library/android-mvc-test/src/main/res/layout/fragment_mvc_v2v_dialog.xml diff --git a/library/android-mvc-test/src/androidTest/java/com/shipdream/lib/android/mvc/view/eventv2v/TestV2VEvents.java b/library/android-mvc-test/src/androidTest/java/com/shipdream/lib/android/mvc/view/eventv2v/TestV2VEvents.java new file mode 100644 index 0000000..43d81fd --- /dev/null +++ b/library/android-mvc-test/src/androidTest/java/com/shipdream/lib/android/mvc/view/eventv2v/TestV2VEvents.java @@ -0,0 +1,73 @@ +/* + * 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.eventv2v; + +import com.shipdream.lib.android.mvc.view.BaseTestCase; +import com.shipdream.lib.android.mvc.view.eventv2v.controller.V2VTestController; +import com.shipdream.lib.android.mvc.view.test.R; + +import org.junit.Test; + +import javax.inject.Inject; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.click; +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 TestV2VEvents extends BaseTestCase { + @Inject + private V2VTestController v2VTestController; + + public TestV2VEvents() { + super(EventBusV2VActivity.class); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + } + + @Override + public void tearDown() throws Exception { + super.tearDown(); + waitTest(); + } + + @Test + public void should_be_able_to_send_and_receive_v2v_events_among_fragments_services_and_dialogFragments() throws Throwable { + onView(withId(R.id.fragment_mvc_v2v_text)).check(matches(withText("Initial Text"))); + + onView(withId(R.id.fragment_mvc_v2v_btnService)).perform(click()); + + onView(withId(R.id.fragment_mvc_v2v_text)).check(matches(withText("Updated By Service"))); + + onView(withId(R.id.fragment_mvc_v2v_btnDialog)).perform(click()); + + onView(withId(R.id.fragment_mvc_v2v_dialog_text)).check(matches(withText("Initial Dialog Text"))); + + v2VTestController.updateDialogButton(this, "Updated By Under Fragment via V2V event"); + + onView(withId(R.id.fragment_mvc_v2v_dialog_text)).check(matches(withText("Updated By Under Fragment via V2V event"))); + + onView(withId(R.id.fragment_mvc_v2v_dialog_button)).perform(click()); + + onView(withId(R.id.fragment_mvc_v2v_text)).check(matches(withText("Dialog Closed"))); + } + +} diff --git a/library/android-mvc-test/src/main/AndroidManifest.xml b/library/android-mvc-test/src/main/AndroidManifest.xml index a52de66..ae10a4d 100644 --- a/library/android-mvc-test/src/main/AndroidManifest.xml +++ b/library/android-mvc-test/src/main/AndroidManifest.xml @@ -45,6 +45,12 @@ + + + + + diff --git a/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/EventBusV2VActivity.java b/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/EventBusV2VActivity.java new file mode 100644 index 0000000..5f75203 --- /dev/null +++ b/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/EventBusV2VActivity.java @@ -0,0 +1,63 @@ +/* + * 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.eventv2v; + +import android.os.Bundle; +import android.view.View; + +import com.shipdream.lib.android.mvc.view.MvcActivity; +import com.shipdream.lib.android.mvc.view.MvcFragment; + +public class EventBusV2VActivity extends MvcActivity { + + @Override + protected Class mapNavigationFragment(String locationId) { + return EventBusV2VFragment.class; + } + + @Override + protected Class getDelegateFragmentClass() { + return HomeFragment.class; + } + + public static class HomeFragment extends DelegateFragment { + private boolean onViewStateRestoredCalled = false; + + @Override + protected void onStartUp() { + getNavigationController().navigateTo(this, "TestFragment", null); + } + + @Override + public void onViewReady(View view, Bundle savedInstanceState, Reason reason) { + super.onViewReady(view, savedInstanceState, reason); + + if (reason.isRestored()) { + if (!onViewStateRestoredCalled) { + throw new IllegalStateException("When activity is restoring, onViewReady must be called after onViewStateRestored to guarantee all state of this fragment is ready to use."); + } + } + } + + @Override + public void onViewStateRestored(Bundle savedInstanceState) { + onViewStateRestoredCalled = true; + super.onViewStateRestored(savedInstanceState); + } + } + +} diff --git a/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/EventBusV2VDialogFragment.java b/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/EventBusV2VDialogFragment.java new file mode 100644 index 0000000..ffe20e9 --- /dev/null +++ b/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/EventBusV2VDialogFragment.java @@ -0,0 +1,50 @@ +/* + * 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.eventv2v; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.shipdream.lib.android.mvc.view.MvcDialogFragment; +import com.shipdream.lib.android.mvc.view.test.R; + +public class EventBusV2VDialogFragment extends MvcDialogFragment { + private TextView textView; + private View button; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_mvc_v2v_dialog, container); + textView = (TextView) view.findViewById(R.id.fragment_mvc_v2v_dialog_text); + button = view.findViewById(R.id.fragment_mvc_v2v_dialog_button); + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + postEventV2V(new Events.OnFragmentTextChanged(v, "Dialog Closed")); + dismiss(); + } + }); + return view; + } + + private void onEvent(Events.OnDialogButtonChanged onButtonUpdated) { + textView.setText(onButtonUpdated.getText()); + } +} diff --git a/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/EventBusV2VFragment.java b/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/EventBusV2VFragment.java new file mode 100644 index 0000000..10a6bad --- /dev/null +++ b/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/EventBusV2VFragment.java @@ -0,0 +1,71 @@ +/* + * 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.eventv2v; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.TextView; + +import com.shipdream.lib.android.mvc.view.MvcFragment; +import com.shipdream.lib.android.mvc.view.eventv2v.controller.V2VTestController; +import com.shipdream.lib.android.mvc.view.test.R; + +public class EventBusV2VFragment extends MvcFragment { + private TextView textView; + private View buttonDialog; + private View buttonService; + + @Override + protected int getLayoutResId() { + return R.layout.fragment_mvc_v2v; + } + + @Override + public void onViewReady(View view, Bundle savedInstanceState, Reason reason) { + super.onViewReady(view, savedInstanceState, reason); + + textView = (TextView) view.findViewById(R.id.fragment_mvc_v2v_text); + + buttonDialog = view.findViewById(R.id.fragment_mvc_v2v_btnDialog); + buttonDialog.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + final EventBusV2VDialogFragment cityDialog = new EventBusV2VDialogFragment(); + cityDialog.show(getFragmentManager(), "EventBusV2VDialogFragment"); + } + }); + + buttonService = view.findViewById(R.id.fragment_mvc_v2v_btnService); + buttonService.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(getActivity(), EventBusV2VService.class); + getActivity().startService(intent); + } + }); + } + + private void onEvent(Events.OnFragmentTextChanged event) { + textView.setText(event.getText()); + } + + private void onEvent(V2VTestController.EventC2V.OnButtonUpdated onButtonUpdated) { + postEventV2V(new Events.OnDialogButtonChanged(onButtonUpdated.getSender(), onButtonUpdated.getText())); + } + +} diff --git a/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/EventBusV2VService.java b/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/EventBusV2VService.java new file mode 100644 index 0000000..e8606fd --- /dev/null +++ b/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/EventBusV2VService.java @@ -0,0 +1,36 @@ +/* + * 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.eventv2v; + +import android.content.Intent; +import android.os.IBinder; + +import com.shipdream.lib.android.mvc.view.MvcService; + +public class EventBusV2VService extends MvcService { + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + super.onStartCommand(intent, flags, startId); + postEventV2V(new Events.OnFragmentTextChanged(this, "Updated By Service")); + return START_STICKY; + } +} diff --git a/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/Events.java b/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/Events.java new file mode 100644 index 0000000..7bee1de --- /dev/null +++ b/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/Events.java @@ -0,0 +1,30 @@ +package com.shipdream.lib.android.mvc.view.eventv2v; + +import com.shipdream.lib.android.mvc.event.BaseEventV2V; + +public interface Events { + abstract class OnTextChanged extends BaseEventV2V { + private final String text; + protected OnTextChanged(Object sender, String text) { + super(sender); + this.text = text; + } + + public String getText() { + return text; + } + } + + class OnFragmentTextChanged extends OnTextChanged { + protected OnFragmentTextChanged(Object sender, String text) { + super(sender, text); + } + } + + class OnDialogButtonChanged extends OnTextChanged { + protected OnDialogButtonChanged(Object sender, String text) { + super(sender, text); + } + } + +} diff --git a/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/controller/V2VTestController.java b/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/controller/V2VTestController.java new file mode 100644 index 0000000..bb2cdb5 --- /dev/null +++ b/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/controller/V2VTestController.java @@ -0,0 +1,23 @@ +package com.shipdream.lib.android.mvc.view.eventv2v.controller; + +import com.shipdream.lib.android.mvc.controller.BaseController; +import com.shipdream.lib.android.mvc.event.BaseEventC2V; + +public interface V2VTestController extends BaseController { + void updateDialogButton(Object sender, String text); + + interface EventC2V { + class OnButtonUpdated extends BaseEventC2V { + private final String text; + + public OnButtonUpdated(Object sender, String text) { + super(sender); + this.text = text; + } + + public String getText() { + return text; + } + } + } +} diff --git a/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/controller/internal/V2VTestControllerImpl.java b/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/controller/internal/V2VTestControllerImpl.java new file mode 100644 index 0000000..21d4719 --- /dev/null +++ b/library/android-mvc-test/src/main/java/com/shipdream/lib/android/mvc/view/eventv2v/controller/internal/V2VTestControllerImpl.java @@ -0,0 +1,16 @@ +package com.shipdream.lib.android.mvc.view.eventv2v.controller.internal; + +import com.shipdream.lib.android.mvc.controller.internal.BaseControllerImpl; +import com.shipdream.lib.android.mvc.view.eventv2v.controller.V2VTestController; + +public class V2VTestControllerImpl extends BaseControllerImpl implements V2VTestController{ + @Override + protected Class getModelClassType() { + return null; + } + + @Override + public void updateDialogButton(Object sender, String text) { + postC2VEvent(new EventC2V.OnButtonUpdated(sender, text)); + } +} diff --git a/library/android-mvc-test/src/main/res/layout/fragment_mvc_v2v.xml b/library/android-mvc-test/src/main/res/layout/fragment_mvc_v2v.xml new file mode 100644 index 0000000..ed1dc31 --- /dev/null +++ b/library/android-mvc-test/src/main/res/layout/fragment_mvc_v2v.xml @@ -0,0 +1,48 @@ + + + + + + + + + +