From ebea99fd18d9a8e72b56fb5069b18df31cc05a66 Mon Sep 17 00:00:00 2001
From: Kejun Xia
+ * UiView represents android views. It has a single method {@link #update()}. Every {@link Controller}
+ * holds an instance of {@link UiView} which is implemented by the controller's corresponding
+ * concrete view. Whenever the {@link Controller} updates its state, usually it's model, the controller
+ * needs to call {@link UiView}.{@link #update()}.
+ *
+ * Usually this is enough for most Android views since as long as the concrete view implements
+ * {@link UiView}.{@link #update()} by binding the full controller model to the view, it guarantees the view's
+ * graphics is always in sync with the controller's model. However, if the model of a controller is
+ * large and sometimes only very limited part of the model changes, you may not always want to call
+ * {@link UiView}.{@link #update()} to rebind the entire model to the view if performance becomes a concern.
+ *
+ * In this case, define a custom view interface extending {@link UiView} with extra method to allow
+ * controllers updating specific part of the view. For example,
+ * Do NOT change values of model from view but only from controllers. It will be automatically called when a view is ready to shown. Controllers should call this
+ * method when they updated their model. Do NOT change values of model from view but only from controllers.
+ * A controller is a delegate of a Android view. It holds a {@link UiView} that needs to be implemented
+ * by the corresponding Android view. Whenever the controller changes its model, it calls {@link UiView#update()}
+ * to update the view. Be careful when you are calling {@link UiView#update()} on the non-UI thread,
+ * because in this case, it needs to use {@link #uiThreadRunner} to post a runnable wrapping
+ * {@link UiView#update()} to ensure the view is updated on UI thread. Use {@link #runTask(Task)} to
+ * run heavy actions, especially network calls, on non-UI thread.
+ *
+ * In the above way the controller works as a presenter in MVP pattern. If you prefer MVVM pattern.
+ * You can define events and {@link #postEvent(Object)} to the view. Since {@link #postEvent(Object)}
+ * guarantees the event is posted onto UI thread, you don't need to worry about on which thread the
+ * event is posted.
+ *
+ * When some code needs to run on non-UI thread, use {@link #runTask(Task)},
+ * {@link #runTask(Task, Task.Callback)} to run it on a different thread. Make sure if
+ * {@link UiView#update()} needs to be called in scope of @link Task#execute(Task.Monitor)} use
+ * {@link #uiThreadRunner} to post back to UI thread.
+ *
+ * The controller has 4 injected fields. They can be replaced by providing special or mocking objects
+ * in unit tests.
+ *
+ * public interface PageView extends UiView {
+ * /**
+ * * Let the controller of the page view just update the title instead calling {@link UiView}.{@link #update()}
+ * * to update the whole page.
+ * * @param title The title of the page.
+ * * /
+ * void updateTitle(String title);
+ * }
+ *
*/
public interface UiView {
/**
* When a view is requested to update itself, it should read it's controller's model by
* {@link Controller#getModel()} to bind the data to the view.
*
- *
+ *
+ *
* Post the event to views. It automatically guarantees the event will be received - * and run on UI thread of Android + * and run on UI thread of Android. + *
+ * + *+ * The event will be captured by views or any objects registered to {@link EventBus} annotated + * by {@link EventBusV} and has corresponding method named onEvent() with single parameter with + * the same type of the event. For example + *
+ *+ * public class OnTextChangedEvent { + * private String text; + * + * public OnTextChangedEvent(String text) { + * this.text = text; + * } + * + * public String getText() { + * return text; + * } + * } + * + * public class SomeView { + * @ Inject + * @ EventBusV + * private EventBus eventBusV; + * + * private TextView textView; + * + * public class SomeView() { + * //This is just needed when you have a view not inheriting MvcFragment, MvcService or etc. + * //In MvcFragment or MvcService will register to the event bus in onCreate automatically. + * eventBusV.register(this); + * } + * + * public void onEvent(OnTextChangedEvent onTextChangedEvent) { + * textView.setText(onTextChangedEvent.getText()); + * } + * } + * + * public class SomeController{ + * private void func() { + * postEvent(new OnTextChangedEvent("Controller Wants to change text")); + * } + * } + *+ * * @param eventV The event */ protected void postEvent(final Object eventV) { uiThreadRunner.post(new Runnable() { @Override public void run() { - eventBus2V.post(eventV); + eventBusV.post(eventV); } }); } + } diff --git a/library/android-mvc-core/src/main/java/com/shipdream/lib/android/mvc/UiThreadRunner.java b/library/android-mvc-core/src/main/java/com/shipdream/lib/android/mvc/UiThreadRunner.java index 8d0c620..0e1fb65 100644 --- a/library/android-mvc-core/src/main/java/com/shipdream/lib/android/mvc/UiThreadRunner.java +++ b/library/android-mvc-core/src/main/java/com/shipdream/lib/android/mvc/UiThreadRunner.java @@ -8,13 +8,15 @@ public interface UiThreadRunner { boolean isOnUiThread(); /** - * Post the runnable to run on Android UI thread + * Post the runnable to run on Android UI thread. In Android app, when the caller is not + * currently on UI thread, it will be posted to the UI thread to be run in next main loop. + * Otherwise, it will be run immediately. * @param runnable */ void post(Runnable runnable); /** - * Post the runnable to run on Android UI thread + * Post the runnable to run on Android UI thread with the given delay. * @param runnable */ void postDelayed(Runnable runnable, long delayMs); diff --git a/library/android-mvc-core/src/main/java/com/shipdream/lib/android/mvc/event/bus/annotation/EventBusC.java b/library/android-mvc-core/src/main/java/com/shipdream/lib/android/mvc/event/bus/annotation/EventBusC.java index 2869172..29daaa7 100644 --- a/library/android-mvc-core/src/main/java/com/shipdream/lib/android/mvc/event/bus/annotation/EventBusC.java +++ b/library/android-mvc-core/src/main/java/com/shipdream/lib/android/mvc/event/bus/annotation/EventBusC.java @@ -16,6 +16,8 @@ package com.shipdream.lib.android.mvc.event.bus.annotation; +import com.shipdream.lib.android.mvc.event.bus.EventBus; + import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -23,8 +25,10 @@ import javax.inject.Qualifier; /** - * Indicates the annotated event bus is for events to controllers. Events through the event bus - * annotated by this annotation will be received on the same thread as the caller who posts them. + * Indicates the annotated event bus is for events to core components such as controllers, managers + * or core services. To receive or send events to Android views use {@link EventBusV} to qualify the + * injecting {@link EventBus}. Events through the event bus annotated by this annotation will be + * received on the same thread as the caller who posts them. */ @Qualifier @Documented diff --git a/library/android-mvc-core/src/main/java/com/shipdream/lib/android/mvc/event/bus/annotation/EventBusV.java b/library/android-mvc-core/src/main/java/com/shipdream/lib/android/mvc/event/bus/annotation/EventBusV.java index 0501854..fecf462 100644 --- a/library/android-mvc-core/src/main/java/com/shipdream/lib/android/mvc/event/bus/annotation/EventBusV.java +++ b/library/android-mvc-core/src/main/java/com/shipdream/lib/android/mvc/event/bus/annotation/EventBusV.java @@ -16,6 +16,8 @@ package com.shipdream.lib.android.mvc.event.bus.annotation; +import com.shipdream.lib.android.mvc.event.bus.EventBus; + import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -23,9 +25,15 @@ import javax.inject.Qualifier; /** - * Indicates the annotated event bus is for events sent to views. On Android - * events through the event bus annotated by this annotation will be guaranteed to be received on - * Android's UI thread automatically. + * Indicates the annotated event bus is for events sent to Android views. To send or receive events + * for core components such as controllers, managers, core services, use {@link EventBusC} to annotate + * the injecting {@link EventBus}. + * + *
+ * In Android app events through the event bus annotated by this annotation will be guaranteed to be + * received on Android's UI thread automatically. + *
+ * */ @Qualifier @Documented From bd2dbf04fb871a33453a85fd4c0aef8c0808fc46 Mon Sep 17 00:00:00 2001 From: Kejun Xia