Created
December 10, 2017 21:53
-
-
Save OleksandrKucherenko/ab51236de034261bf8de35104f19c285 to your computer and use it in GitHub Desktop.
MVP pattern, basic interfaces
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** Copyright 2017, Oleksandr Kucherenko */ | |
package olku.android.mvp; | |
import android.net.Uri; | |
import android.os.Bundle; | |
import android.support.annotation.*; | |
import java.lang.annotation.Retention; | |
import java.util.HashMap; | |
import java.util.Map; | |
import rx.functions.Func1; | |
import static java.lang.annotation.RetentionPolicy.SOURCE; | |
/** High level scope of all Model, View, Presenter and Interactor's. */ | |
public interface Mvp { | |
/** | |
* Model/View/Presenter/Interactor design patter. Inherit the interface for marking class as a Interactor for pattern. | |
* | |
* @see <a href="http://fernandocejas.com/2014/09/03/architecting-android-the-clean-way/">Clean Architecture</a> | |
*/ | |
interface Interactor { | |
} | |
/** | |
* Model/View/Presenter/Interactor design patter. Inherit the interface for marking class as a View for pattern. | |
* | |
* @see <a href="http://fernandocejas.com/2014/09/03/architecting-android-the-clean-way/">Clean Architecture</a> | |
*/ | |
@MainThread | |
interface View { | |
/** Navigate user by specified deeplink. */ | |
@AutoProxy.Yield(Returns.DIRECT) | |
boolean dispatchDeepLink(@NonNull final Uri deepLink); | |
} | |
/** Sub-component of the view interface. Just a marker for class/interface. */ | |
@MainThread | |
interface Controller { | |
} | |
/** | |
* Model/View/Presenter/Interactor design patter. Inherit the interface for marking class as a Presenter for pattern. | |
* | |
* @see <a href="http://fernandocejas.com/2014/09/03/architecting-android-the-clean-way/">Clean Architecture</a> | |
*/ | |
@SuppressWarnings({"unused"}) | |
interface Presenter { | |
/** Resume all. Activity/Fragment goes foreground. */ | |
void resume(); | |
/** Pause all. Activity/Fragment goes background. */ | |
void pause(); | |
/** Inherit this interface if you plan to save/restore state of the presenter. */ | |
interface WithState { | |
/** restore presenter state from bundle instance. */ | |
void restore(@NonNull final Bundle state); | |
/** save presenter state to bundle. */ | |
void save(@NonNull final Bundle state); | |
} | |
} | |
/** | |
* Model/View/Presenter/Interactor design patter. Inherit the interface for marking class as a Model for pattern. | |
* | |
* @see <a href="http://fernandocejas.com/2014/09/03/architecting-android-the-clean-way/">Clean Architecture</a> | |
*/ | |
interface Model { | |
} | |
/** All known event types. */ | |
@Retention(SOURCE) | |
@IntDef({ | |
Events.WHEEL_EXPANDING /*, ...*/ | |
}) | |
@interface Events { | |
/** Wheel expanding. */ | |
int WHEEL_EXPANDING = 1; | |
/** used for unit testing only. */ | |
int UNKNOWN = -1; | |
/** Capture critical to application error. */ | |
int GOOGLE_SERVICES_ERROR = -2; | |
/** Generic message. Used for forwarding captured error/exception. */ | |
int ERROR_CAPTURED = -3; | |
/** Utility event. Used for notifying that fragmentDialog closed by user. */ | |
int DIALOG_CLOSED = -4; | |
/** Application installed */ | |
int INSTALLED = -100; | |
/** Application first run. */ | |
int FIRST_RUN = -101; | |
/** Upgrade from older version */ | |
int UPGRADED = -102; | |
} | |
/** EventBus abstraction. Used for cross presenter communications. */ | |
class Event { | |
/** Event unique identifier. */ | |
public final int id; | |
/** additional info associated with event. */ | |
@Nullable | |
public final Object tag; | |
/** extended key value data associated with event. */ | |
@NonNull | |
public final Map<String, Object> eventData = new HashMap<>(); | |
public Event(@Events final int id) { | |
this(id, null); | |
} | |
public Event(@Events final int id, @Nullable final Object tag) { | |
this.id = id; | |
this.tag = tag; | |
} | |
@NonNull | |
public Event withEventData(final String name, final Object value) { | |
eventData.put(name, value); | |
return this; | |
} | |
} | |
/** All MvpModule classes should inherit it for type safe casting. */ | |
interface Module { | |
} | |
/** | |
* Class designed for simplified injection of Mocked MvpModule into fragments/activities and any other UI | |
* elements without deep overrides of classes in Unit Tests. | |
*/ | |
class Factory { | |
/** Registered creators of MvpModules. */ | |
@VisibleForTesting /* package */ static final Map<Class<? extends View>, | |
Func1<? super View, ? extends Module>> registered = new HashMap<>(); | |
/** Find reflection class interface that inherits the Mvp.View interface. */ | |
@NonNull | |
@SuppressWarnings("unchecked") | |
static Class<? extends View> findViewClazz(final Class<? extends View> clazz) { | |
for (Class<?> cl : clazz.getInterfaces()) { | |
final Class<?>[] interfaces = cl.getInterfaces(); | |
final boolean isNotEmpty = null != interfaces && interfaces.length == 1; | |
if (isNotEmpty && interfaces[0].isAssignableFrom(View.class)) | |
return (Class<? extends View>) cl; | |
} | |
return clazz; | |
} | |
/** Factory method that allows easy replacement of the MvpModule for UI elements. */ | |
@SuppressWarnings("unchecked") | |
public static <M extends Module, V extends View> M peek(@NonNull final V view, @NonNull final Func1<V, M> creator) { | |
// first: try the class itself | |
final Class<? extends View> clazz = view.getClass(); | |
final Func1<? super View, ? extends Module> mock = registered.get(clazz); | |
// mock is available | |
if (null != mock) | |
return (M) mock.call(view); | |
// second: try the inheritor of Mvp.View interface | |
final Class<? extends View> viewClazz = findViewClazz(clazz); | |
final Func1<? super View, ? extends Module> mockView = registered.get(viewClazz); | |
if (null != mockView) | |
return (M) mockView.call(view); | |
// third: call the provided creator | |
return creator.call(view); | |
} | |
/** Register module creator in factory. */ | |
public static void register(@NonNull final Class<? extends View> clazz, | |
@NonNull final Func1<? super View, ? extends Module> creator) { | |
registered.put(clazz, creator); | |
} | |
/** Unregister module creator in factory. */ | |
public static void unregister(@NonNull final Class<? extends View> clazz) { | |
registered.remove(clazz); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
all Presenters should inherit
Mvp.Presenter
,Model -
Mvp.Model
View -
Mvp.View
Interactor -
Mvp.Interactor