Repository: tinmegali/simple-mvp Branch: master Commit: df726db3a14d Files: 42 Total size: 78.3 KB Directory structure: gitextract__r8j11ak/ ├── AndroidMVP/ │ ├── .idea/ │ │ └── runConfigurations.xml │ ├── app/ │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src/ │ │ ├── androidTest/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── tinmegali/ │ │ │ └── androidmvp/ │ │ │ └── ApplicationTest.java │ │ ├── main/ │ │ │ ├── AndroidManifest.xml │ │ │ ├── java/ │ │ │ │ └── com/ │ │ │ │ └── tinmegali/ │ │ │ │ └── androidmvp/ │ │ │ │ └── main/ │ │ │ │ ├── MVP_MainActivity.java │ │ │ │ ├── model/ │ │ │ │ │ └── MainModel.java │ │ │ │ ├── presenter/ │ │ │ │ │ └── MainPresenter.java │ │ │ │ └── view/ │ │ │ │ └── MainActivity.java │ │ │ └── res/ │ │ │ ├── layout/ │ │ │ │ ├── activity_main.xml │ │ │ │ └── content_main.xml │ │ │ ├── menu/ │ │ │ │ └── menu_main.xml │ │ │ ├── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ │ ├── values-v21/ │ │ │ │ └── styles.xml │ │ │ └── values-w820dp/ │ │ │ └── dimens.xml │ │ └── test/ │ │ └── java/ │ │ └── com/ │ │ └── tinmegali/ │ │ └── androidmvp/ │ │ ├── TestModel.java │ │ └── TestPresenter.java │ ├── build.gradle │ ├── gradle/ │ │ └── wrapper/ │ │ └── gradle-wrapper.properties │ ├── gradle.properties │ ├── mvp/ │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src/ │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── tinmegali/ │ │ │ └── mvp/ │ │ │ ├── mvp/ │ │ │ │ ├── ActivityView.java │ │ │ │ ├── ContextView.java │ │ │ │ ├── GenericMVPActivity.java │ │ │ │ ├── GenericMVPFragment.java │ │ │ │ ├── GenericModel.java │ │ │ │ ├── GenericPresenter.java │ │ │ │ ├── ModelOps.java │ │ │ │ ├── PresenterOps.java │ │ │ │ ├── StateMaintainer.java │ │ │ │ └── package-info.java │ │ │ └── util/ │ │ │ └── ActivityKeyBoardDetector.java │ │ └── res/ │ │ └── values/ │ │ ├── AndroidManifest.xml │ │ └── strings.xml │ └── settings.gradle └── README.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: AndroidMVP/.idea/runConfigurations.xml ================================================ ================================================ FILE: AndroidMVP/app/build.gradle ================================================ apply plugin: 'com.android.application' android { compileSdkVersion 23 buildToolsVersion "23.0.2" defaultConfig { applicationId "com.tinmegali.androidmvp" minSdkVersion 11 targetSdkVersion 23 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.2.0' compile 'com.android.support:design:23.2.0' compile project(":mvp") // compile 'com.tinmegali.mvp:mvp:0.0.5' // Unit testing dependencies testCompile 'junit:junit:4.12' // Set this dependency if you want to use Mockito testCompile 'org.mockito:mockito-core:1.10.19' // Set this dependency if you want to use Hamcrest matching testCompile 'org.hamcrest:hamcrest-library:1.1' testCompile "org.robolectric:robolectric:3.0" } ================================================ FILE: AndroidMVP/app/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in /Users/tinmegali/Library/Android/sdk/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} ================================================ FILE: AndroidMVP/app/src/androidTest/java/com/tinmegali/androidmvp/ApplicationTest.java ================================================ package com.tinmegali.androidmvp; import android.app.Application; import android.test.ApplicationTestCase; /** * Testing Fundamentals */ public class ApplicationTest extends ApplicationTestCase { public ApplicationTest() { super(Application.class); } } ================================================ FILE: AndroidMVP/app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: AndroidMVP/app/src/main/java/com/tinmegali/androidmvp/main/MVP_MainActivity.java ================================================ package com.tinmegali.androidmvp.main; import com.tinmegali.mvp.mvp.ActivityView; import com.tinmegali.mvp.mvp.ModelOps; import com.tinmegali.mvp.mvp.PresenterOps; /** *

* Interface that holds all operations available to MVP layers. * Controls the communication process between each layer *

* * Using * interface RequiredViewOps extends ActivityView * with VIEW methods to be accessed by PRESENTER * * interface ProvidedPresenterOps extends PresenterOps * Operations offered to VIEW to communicate with PRESENTER * * interface RequiredPresenterOps * with Required PRESENTER methods available to MODEL * * interface ProvidedModelOps extends ModelOps * Operations offered to MODEL to communicate with PRESENTER * * Created by: Tin Megali on 25/02/16.
* Project: AndroidMVP
* ---------------------------------------------------
* tinmegali.com
* * framework MVP developed by * * Dr. Douglas Schmidth *

* */ public interface MVP_MainActivity { /** * Required VIEW methods available to PRESENTER * PRESENTER to VIEW */ interface RequiredViewOps extends ActivityView { } /** * Operations offered to VIEW to communicate with PRESENTER * VIEW to PRESENTER */ interface ProvidedPresenterOps extends PresenterOps { boolean clickSaveName(String nameTxt); boolean clickClearName(); } /** * Required PRESENTER methods available to MODEL * MODEL to PRESENTER */ interface RequiredPresenterOps { boolean onNameSaved(String nameTxt); boolean onNameCleared(); } /** * Operations offered to MODEL to communicate with PRESENTER * PRESENTER to MODEL */ interface ProvidedModelOps extends ModelOps { boolean saveName(String nameTxt); boolean clearName(); } } ================================================ FILE: AndroidMVP/app/src/main/java/com/tinmegali/androidmvp/main/model/MainModel.java ================================================ package com.tinmegali.androidmvp.main.model; import android.os.AsyncTask; import com.tinmegali.androidmvp.main.MVP_MainActivity; import com.tinmegali.mvp.mvp.GenericModel; /** *

* Layer MODEL from Model View Presenter (MVP) pattern.
* Responsible to deal with all business logic and data in general.
*

* * Created by Tin Megali on 25/02/16.
* Project: AndroidMVP
* ---------------------------------------------------
* tinmegali.com
* * framework MVP developed by * * Dr. Douglas Schmidth *

*/ public class MainModel extends GenericModel implements MVP_MainActivity.ProvidedModelOps { /** * Method that recovers a reference to the PRESENTER *
    *
  • You must ALWAYS call {@link super#onCreate(Object)} here
  • *
* @param presenterOps Presenter interface */ @Override public void onCreate(MVP_MainActivity.RequiredPresenterOps presenterOps) { super.onCreate(presenterOps); } /** * Called by layer PRESENTER when VIEW pass for a reconstruction/destruction.
* Usefull for kill/stop activities that could be running on the background * Threads * @param isChangingConfiguration Informs that a change is occurring on the configuration */ @Override public void onDestroy(boolean isChangingConfiguration) { } String mName; @Override public boolean clearName() { mName = null; return getPresenter().onNameCleared(); } @Override public boolean saveName(final String nameTxt) { new AsyncTask() { @Override protected String doInBackground(Void... params) { mName = nameTxt; try { Thread.sleep(2000); return mName; } catch (InterruptedException e) { e.printStackTrace(); } return null; } @Override protected void onPostExecute(String name) { if ( name != null) getPresenter().onNameSaved(name); } }.execute(); return true; } // just for tests public String getName(){ return mName; } } ================================================ FILE: AndroidMVP/app/src/main/java/com/tinmegali/androidmvp/main/presenter/MainPresenter.java ================================================ package com.tinmegali.androidmvp.main.presenter; import com.tinmegali.androidmvp.main.MVP_MainActivity; import com.tinmegali.androidmvp.main.model.MainModel; import com.tinmegali.mvp.mvp.ContextView; import com.tinmegali.mvp.mvp.GenericMVPActivity; import com.tinmegali.mvp.mvp.GenericPresenter; /** *

* Layer PRESENTER from Model View Presenter (MVP) Pattern.
* Mediates the comunication between layers VIEW and MODEL. *

*

* Layer Presenter no padrão Model View Presenter (MVP).
* * Created by: Tin Megali on 25/02/16.
* Project: AndroidMVP
* ---------------------------------------------------
* tinmegali.com
* * framework MVP developed by * * Dr. Douglas Schmidth *

*/ public class MainPresenter extends GenericPresenter implements MVP_MainActivity.RequiredPresenterOps, MVP_MainActivity.ProvidedPresenterOps { /** * Operation called during VIEW creation in * {@link com.tinmegali.mvp.mvp.GenericMVPActivity#onCreate(Class, Object)}
* Responsible to initialize MODEL. *
    *
  • * Always call {@link GenericPresenter#onCreate(Class, Object)} to * initialize the object *
  • *
  • * Always call {@link GenericPresenter#setView(ContextView)} to save a * RequiredViewOps reference *
  • *
* @param view The current VIEW instance */ @Override public void onCreate(MVP_MainActivity.RequiredViewOps view) { super.onCreate(MainModel.class, this); // super.onCreate(, ); setView( view ); } /** * Operation called by VIEW after its reconstruction. *
    *
  • * Always call {@link GenericPresenter#setView(ContextView)} to * save the new instance of RequiredViewOps *
  • *
* @param view The current VIEW instance */ @Override public void onConfigurationChanged(MVP_MainActivity.RequiredViewOps view) { setView(view); } /** * Helper method to inform Presenter that a onBackPressed event occurred * Called by {@link GenericMVPActivity} */ @Override public void onBackPressed() { } @Override public boolean clickClearName() { return clearName(); } // For test purposes public boolean clearName(){ return getModel().clearName(); } @Override public boolean clickSaveName(String nameTxt) { return saveName(nameTxt); } // For test purposes public boolean saveName(String txt){ return getModel().saveName(txt); } @Override public boolean onNameSaved(String nameTxt) { return nameTxt != null; } @Override public boolean onNameCleared() { return true; } } ================================================ FILE: AndroidMVP/app/src/main/java/com/tinmegali/androidmvp/main/view/MainActivity.java ================================================ package com.tinmegali.androidmvp.main.view; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.v7.widget.Toolbar; import android.view.View; import com.tinmegali.androidmvp.R; import com.tinmegali.androidmvp.main.MVP_MainActivity; import com.tinmegali.androidmvp.main.presenter.MainPresenter; import com.tinmegali.mvp.mvp.GenericMVPActivity; /** *

* VIEW layer of MVP pattern. *

* Created by: Tin Megali on 25/02/16.
* Project: AndroidMVP
* ---------------------------------------------------
* tinmegali.com
* * framework MVP developed by * * Dr. Douglas Schmidth *

*/ public class MainActivity extends GenericMVPActivity implements MVP_MainActivity.RequiredViewOps{ /** * Method that initialized MVP objects * {@link super#onCreate(Class, Object)} should always be called */ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); super.onCreate(MainPresenter.class,this); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); } }); } } ================================================ FILE: AndroidMVP/app/src/main/res/layout/activity_main.xml ================================================ ================================================ FILE: AndroidMVP/app/src/main/res/layout/content_main.xml ================================================ ================================================ FILE: AndroidMVP/app/src/main/res/menu/menu_main.xml ================================================ ================================================ FILE: AndroidMVP/app/src/main/res/values/colors.xml ================================================ #3F51B5 #303F9F #FF4081 ================================================ FILE: AndroidMVP/app/src/main/res/values/dimens.xml ================================================ 16dp 16dp 16dp ================================================ FILE: AndroidMVP/app/src/main/res/values/strings.xml ================================================ AndroidMVP Settings ================================================ FILE: AndroidMVP/app/src/main/res/values/styles.xml ================================================ ================================================ FILE: AndroidMVP/app/src/main/res/values-w820dp/dimens.xml ================================================ 64dp ================================================ FILE: AndroidMVP/app/src/test/java/com/tinmegali/androidmvp/TestModel.java ================================================ package com.tinmegali.androidmvp; import com.tinmegali.androidmvp.main.model.MainModel; import com.tinmegali.androidmvp.main.presenter.MainPresenter; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.robolectric.RobolectricGradleTestRunner; import org.robolectric.annotation.Config; import static org.junit.Assert.*; import static org.mockito.Mockito.*; /** * * A simple Test case to illustrate how to Test Model * --------------------------------------------------- * Created by Tin Megali on 14/03/16. * Project: AndroidMVP * --------------------------------------------------- * tinmegali.com * tinmegali.com * ================================================ FILE: AndroidMVP/mvp/src/main/java/com/tinmegali/mvp/mvp/ActivityView.java ================================================ package com.tinmegali.mvp.mvp; import android.view.View; /** *

* Interface to be implemented by the Activity, * contains some basic common feedback operations *

*

* Created by Tin Megali on 24/02/16.
* Project: AndroidMVP
* *
www.tinmegali.com * * @see Project's Git
* @see Sample Application * @see * Sample MVP interface * */ public interface ActivityView extends ContextView { /** * Shows a toast in the Activity with a short time * @param msg Message to show */ void onShowToast(String msg); /** * Shows a {@link android.widget.Toast} in the Activity with custom time * @param msg Message to show * @param duration Time Length * {@link android.widget.Toast#LENGTH_SHORT} * {@link android.widget.Toast#LENGTH_LONG} */ void onShowToast(String msg, int duration); /** * Shows a Snackbar in Activity with a short time * @param msg Snackbar message * @param parentView Snackbar parent view */ void onShowSnackbar(String msg, View parentView); /** * Shows a Snackbar in Activity with custom time * @param msg Snackbar message * @param parentView Snackbar parent view * @param duration Time Length * Snackbar#LENGTH_SHORT * Snackbar#LENGTH_LONG * Snackbar#LENGTH_INDEFINITE */ void onShowSnackbar(String msg, View parentView, int duration); /** * Shows a given Snackbar * Useful for snacks with custom actions. * @param snackbar The Snackbar to show */ void onShowSnackbar(android.support.design.widget.Snackbar snackbar); } ================================================ FILE: AndroidMVP/mvp/src/main/java/com/tinmegali/mvp/mvp/ContextView.java ================================================ package com.tinmegali.mvp.mvp; import android.content.Context; /** *

Interface that grants access to Contexts

*

* Created by Tin Megali on 24/02/16.
* Project: AndroidMVP
* * www.tinmegali.com *

* ---------------------------------------------------
*

* Based on * framework MVP developed by * * Dr. Douglas Schmidth *

* * @see Project's Git
* @see Sample Application * @see * Sample MVP interface * * */ public interface ContextView { /** * Access to application {@link Context} * @return application context */ Context getApplicationContext(); /** * Access to current activity {@link Context} * @return activity context */ Context getActivityContext(); } ================================================ FILE: AndroidMVP/mvp/src/main/java/com/tinmegali/mvp/mvp/GenericMVPActivity.java ================================================ package com.tinmegali.mvp.mvp; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.support.design.widget.Snackbar; import android.util.Log; import android.view.View; import com.tinmegali.mvp.util.ActivityKeyBoardDetector; /** *

* Generic Abstract Activity. * Works as a VIEW layer in the MVP pattern.
* Responsible to initialize the PRESENTER and to maintain * it synchronized with Activity lifecycle changes.
* * IMPORTANT: View Object should implement RequiredViewOps *

* *

* Created by Tin Megali on 24/02/16.
* Project: AndroidMVP
* * www.tinmegali.com *

* ---------------------------------------------------
*

* Based on * framework MVP developed by * * Dr. Douglas Schmidth *

* * @see Project's Git
* @see Sample Application * @see * Sample MVP interface * * * @param Interface with available * VIEW methods available to PRESENTER * @param Interface with available * PRESENTER methods available to VIEW * @param PRESENTER Object to be instantiated by the VIEW */ public abstract class GenericMVPActivity > extends ActivityKeyBoardDetector implements ActivityView { protected final String TAG = getClass().getSimpleName(); // Responsible to maintain objects state between config changes protected final StateMaintainer mStateMaintainer = new StateMaintainer( this.getFragmentManager(), TAG ); // PRESENTER reference private PresenterType mPresenterInstance; /** * Hook method to initialize PRESENTER. Needs to be called in * {@link Activity#onCreate(Bundle)}. * * @param opsType PRESENTER Object class * @param view Interface with VIEW reference to PRESENTER */ public void onCreate(Class opsType, RequiredViewOps view ) { try { if ( mStateMaintainer.firstTimeIn() ) { Log.d(TAG, "onCreate() calling for the first time."); initialize(opsType, view); } else { Log.d(TAG, "onCreate() calling more then once."); reinitialize(opsType, view); } } catch ( InstantiationException | IllegalAccessException e ) { Log.d(TAG, "onCreate() " + e ); throw new RuntimeException( e ); } } /** * Gets PRESENTER layer * @return PRESENTER instance with operation availabe to VIEW */ @SuppressWarnings("unchecked") public ProvidedPresenterOps getPresenter() { return (ProvidedPresenterOps) mPresenterInstance; } /** * @return State Maintainer instance */ public StateMaintainer getStateMaintainer() { return mStateMaintainer; } /** * @return Activity Context */ @Override public Context getActivityContext() { return this; } /** * @return Application Context */ @Override public Context getApplicationContext() { return super.getApplicationContext(); } /** * Initialize PRESENTER layer. * Creates a new instance of the PRESENTER, * saves in the StateMaintainer and call {@link GenericPresenter#onCreate(Object)} * hook method. * * @param opsType PRESENTER Object Class type * @param view Current VIEW instance */ private void initialize( Class opsType, RequiredViewOps view ) throws InstantiationException, IllegalAccessException{ mPresenterInstance = opsType.newInstance(); mStateMaintainer.put( opsType.getSimpleName(), mPresenterInstance ); mPresenterInstance.onCreate(view); } /** * Recovers the PRESENTER and informs its instance that a * configuration change occurred, passing a VIEW reference * one more time. * Case the PRESENTER has been lost, another instance is created. * * @param opsType PRESENTER Object Class type * @param view Current VIEW instance */ private void reinitialize( Class opsType, RequiredViewOps view) throws InstantiationException, IllegalAccessException { mPresenterInstance = mStateMaintainer.get( opsType.getSimpleName() ); if ( mPresenterInstance == null ) { Log.w(TAG, "reinitialize: recreating presenter"); initialize(opsType, view ); } else { mPresenterInstance.onConfigurationChanged(view); } } /** * Show a Snackbar. Helper method to be called by Presenter * @param msg Snackbar message * @param parentView Snackbar parent view */ public void onShowSnackbar(String msg, View parentView) { showSnackbar(msg, parentView); } /** * Show a Toast. Helper method to be called by Presenter * @param msg Message to show */ public void onShowToast(String msg) { showToast(msg); } /** * Show a Toast. Helper method to be called by Presenter * @param msg Message to show * @param duration Time Length * {@link android.widget.Toast#LENGTH_SHORT} */ public void onShowToast(String msg, int duration) { showToast(msg, duration); } /** * Show a Snackbar. Helper method to be called by Presenter * @param msg Snackbar message * @param parentView Snackbar parent view * @param duration Time Length * Snackbar#LENGTH_SHORT * Snackbar#LENGTH_LONG */ public void onShowSnackbar(String msg, View parentView, int duration) { showSnackbar(msg, parentView, duration); } /** * Show a Snackbar. Helper method to be called by Presenter * @param snackbar The Snackbar to show */ public void onShowSnackbar(Snackbar snackbar) { showSnackbar(snackbar); } } ================================================ FILE: AndroidMVP/mvp/src/main/java/com/tinmegali/mvp/mvp/GenericMVPFragment.java ================================================ package com.tinmegali.mvp.mvp; import android.content.Context; import android.util.Log; import java.lang.ref.WeakReference; /** *

* Generic Abstract Fragment. * Works as a VIEW layer in the MVP pattern.
* Responsible to initialize the PRESENTER and to maintain * it synchronized with Activity lifecycle changes.
* IMPORTANT: View Object should implement RequiredViewOps *

*

* Created by Tin Megali on 24/02/16.
* Project: AndroidMVP
* * www.tinmegali.com *

* * @see Project's Git
* @see Sample Application * @see * Sample MVP interface * * * @param Interface that define operation to be executed * on the Activity * @param Interface with available * VIEW methods available to PRESENTER * @param Interface with available * PRESENTER methods available to VIEW * @param PRESENTER Object to be instantiated by the VIEW */ public abstract class GenericMVPFragment< RequiredActivityOps, RequiredViewOps, ProvidedPresenterOps, PresenterType extends PresenterOps> extends android.support.v4.app.Fragment implements ContextView { protected final String TAG = getClass().getSimpleName(); // PRESENTER reference private PresenterType mPresenterInstance; // Responsible to maintain objects state between config changes protected StateMaintainer mStateMaintainer; // Activity operations available protected WeakReference mActivity; /** * Subscribes onAttach to get a reference from current Activity * and its available operations to Fragment * @param context Activity context */ @SuppressWarnings("unchecked") @Override public void onAttach(Context context) { super.onAttach(context); try { mActivity = new WeakReference<>( (RequiredActivityOps) getActivity() ); } catch (ClassCastException e) { throw new ClassCastException("Activity must implement " ); } } /** * Hook method to initialize PRESENTER. Needs to be called in * Fragment#onCreate(Bundle) * * @param opsType PRESENTER Object class * @param view Interface with VIEW reference to PRESENTER */ public void onCreate(Class opsType, RequiredViewOps view ) { if ( mStateMaintainer == null) mStateMaintainer = new StateMaintainer(getActivity().getFragmentManager(), TAG + "_retainer" ); try { if ( mStateMaintainer.firstTimeIn() ) { Log.d(TAG, "First time calling onCreate()"); initialize(opsType, view); } else { Log.d(TAG, "Second (or subsequent) time calling onCreate()"); reinitialize(opsType, view); } } catch ( java.lang.InstantiationException | IllegalAccessException e ) { Log.d(TAG, "onCreate() " + e ); throw new RuntimeException( e ); } } /** * Gets PRESENTER layer * @return PRESENTER instance with operation availabe to VIEW */ @SuppressWarnings("unchecked") public ProvidedPresenterOps getPresenter() { return (ProvidedPresenterOps) mPresenterInstance; } /** * @return State Maintainer instance */ public StateMaintainer getStateMaintainer() { return mStateMaintainer; } /** * Initialize PRESENTER layer. * Creates a new instance of the PRESENTER, * saves in the StateMaintainer and call {@link GenericPresenter#onCreate(Object)} * hook method. * * @param opsType PRESENTER Object Class type * @param view Current VIEW instance */ private void initialize( Class opsType, RequiredViewOps view ) throws java.lang.InstantiationException, IllegalAccessException{ mPresenterInstance = opsType.newInstance(); mStateMaintainer.put(opsType.getSimpleName(), mPresenterInstance); mPresenterInstance.onCreate( view ); } /** * Recovers the PRESENTER and informs its instance that a * configuration change occurred, passing a VIEW reference * one more time. * Case the PRESENTER has been lost, another instance is created. * * @param opsType PRESENTER Object Class type * @param view Current VIEW instance */ private void reinitialize( Class opsType, RequiredViewOps view) throws java.lang.InstantiationException, IllegalAccessException { mPresenterInstance = mStateMaintainer.get( opsType.getSimpleName() ); if ( mPresenterInstance == null ) { initialize( opsType, view ); } else { mPresenterInstance.onConfigurationChanged(view); } } @SuppressWarnings("unchecked") @Override public void onDestroy() { super.onDestroy(); ((PresenterOps)getPresenter()) .onDestroy(getActivity().isChangingConfigurations()); } @SuppressWarnings("unchecked") @Override public void onPause() { super.onPause(); ((PresenterOps)getPresenter()) .onDestroy(getActivity().isChangingConfigurations()); } /** * @return Activity Context */ @Override public Context getActivityContext() { return getActivity(); } /** * @return Application Context */ @Override public Context getApplicationContext() { return getActivity().getApplicationContext(); } } ================================================ FILE: AndroidMVP/mvp/src/main/java/com/tinmegali/mvp/mvp/GenericModel.java ================================================ package com.tinmegali.mvp.mvp; import android.util.Log; /** *

* Abstract class of MODEL layer on MVP pattern. * Should be extended by any MODEL object. *

*

* Created by Tin Megali on 24/02/16.
* Project: AndroidMVP
* * www.tinmegali.com *

* ---------------------------------------------------
*

* Based on * framework MVP developed by * * Dr. Douglas Schmidth *

* * @see Project's Git
* @see Sample Application * @see * Sample MVP interface * * * @param Interface with method given to MODEL * to access the Presenter. Should act * as a callback to data operations */ public abstract class GenericModel implements ModelOps { private String TAG = getClass().getSimpleName(); // PRESENTER operations available to MODEL private RequiredPresenterOps mPresenter; /** * Initialize object. Called by {@link GenericPresenter#initialize(Class, Object)} * Saves the PRESENTER reference. * * @param presenterOps reference passed by GenericPresenter * with available operations in PRESENTER layer */ @Override public void onCreate(RequiredPresenterOps presenterOps) { // Log.d(TAG, "onCreate() Model" ); mPresenter = presenterOps; } /** * Hook method that receives destruction and change configurations events. * Shut down methods should be implemented here. * Called from {@link GenericPresenter#onDestroy(boolean)} * * @param isChangingConfiguration Informs if Activity is being destroyed * or changing its configuration * true: configuration is changing * false: a Activity is being destroyed */ @Override public void onDestroy(boolean isChangingConfiguration) { // Log.d(TAG, "onDestrou(isChangingConfiguration:"+isChangingConfiguration+")"); } /** * Recovers the PRESENTER layer reference * @return Operations available on PRESENTER */ public RequiredPresenterOps getPresenter() { return mPresenter; } } ================================================ FILE: AndroidMVP/mvp/src/main/java/com/tinmegali/mvp/mvp/GenericPresenter.java ================================================ package com.tinmegali.mvp.mvp; import android.content.Context; import android.util.Log; import java.lang.ref.WeakReference; /** * *

A Model View Presenter Library using plain and simple interfaces.

* *

* Abstract class of PRESENTER layer on MVP pattern.
* Should be extended by any PRESENTER object * IMPORTANT: PRESENTER pbject should implement * RequiredPresenterOps and ProvidedModelOps *

* IMPORTANT: View Object should implement RequiredViewOps *

* *

* Created by Tin Megali on 24/02/16.
* Project: AndroidMVP
* * www.tinmegali.com *

* ---------------------------------------------------
*

* Based on * framework MVP developed by * * Dr. Douglas Schmidth *

* * @see Project's Git
* @see Sample Application * @see * Sample MVP interface * * * * @param Interface with available PRESENTER * operation to the MODEL layer * * @param Interface with available MODEL * operations available to PRESENTER * * @param Interface with available VIEW * operations available to PRESENTER * * @param MODEL object to be instantiated by * the PRESENTER */ public abstract class GenericPresenter > implements PresenterOps { protected final String TAG = getClass().getSimpleName(); // Reference to the destruction kind that is occurring in VIEW private boolean mConfigurationChangeOccurred; // Informs if VIEW is active private boolean mIsRunning; // Reference to VIEW operations private WeakReference mView; // MODEL object to be instantiated private ModelType mOpsInstance; /** * Method that NEEDS TO BE CALLED by the PRESENTER object * in the {@link PresenterOps#onCreate(Object)} method. * Initialize MODEL and PRESENTER. * * @param opsType Class of the MODEL object * @param presenter Interface with provided PRESENTER operations * available to MODEL */ public void onCreate( Class opsType, RequiredPresenterOps presenter ) { mIsRunning = true; mConfigurationChangeOccurred = false; try { // initialized MODEL initialize( opsType, presenter ); } catch ( InstantiationException | IllegalAccessException e ) { Log.d(TAG, "handleConfiguration " + e); throw new RuntimeException( e ); } } /** * Define a VIEW reference available to PRESENTER. * Should be called i {@link PresenterOps#onCreate(Object)} * * @param view VIEW operations available to PRESENTER */ public void setView(RequiredViewOps view) { mView = new WeakReference<>(view); } /** * Recovers the VIEW reference, returning NULL if layers isn't available. * @return VIEW reference or NULL */ public RequiredViewOps getView() { if ( mIsRunning && !mConfigurationChangeOccurred && mView != null) { return mView.get(); } else { Log.w(TAG, "View unavailable."); return null; } } /** * Recover the application Context * @return Application Context */ public Context getApplicationContext() { return mView.get().getApplicationContext(); } /** * Recover the Activity Context * @return Activity Context */ public Context getActivityContext() { return mView.get().getActivityContext(); } /** * Hook method informing of destruction of the VIEW. * Should be subscribed by the PRESENTER object and called by itself * as a super method. * * @param isChangingConfiguration true: VIEW changing configuration * false: VIEW being destroyed */ public void onDestroy(boolean isChangingConfiguration) { mIsRunning = isChangingConfiguration; mConfigurationChangeOccurred = isChangingConfiguration; mOpsInstance.onDestroy(isChangingConfiguration); } /** * Informs actual VIEW state * @return true: VIEW is active * false: VIEW is destroyed */ public boolean isViewRunning() { return mIsRunning; } /** * Informs if occurred a configuration change * @return true: a configuration change occured */ public boolean configurationsOccurred() { return mConfigurationChangeOccurred; } /** * Initialized the MODEL object, creating a new MODEL instance * * @param opsType MODEL object Class * @param presenter Interface given to MODEL with available * PRESENTER operations * MODEL -> PRESENTER * @throws InstantiationException * @throws IllegalAccessException */ private void initialize( Class opsType, RequiredPresenterOps presenter ) throws InstantiationException, IllegalAccessException { mOpsInstance = opsType.newInstance(); mOpsInstance.onCreate( presenter ); } /** * Returns available MODEL methods * @return a MODEL object instance */ @SuppressWarnings("unchecked") public ProvidedModelOps getModel() { return (ProvidedModelOps) mOpsInstance; } /** * Added for test purposes. Sets the given Model * without the need to cal {@link #onCreate(Class, Object)}. * IMPORTANT: Use ONLY FOR TESTS. * @param model Model instance */ public void testWithModel(ModelType model) { mOpsInstance = model; } } ================================================ FILE: AndroidMVP/mvp/src/main/java/com/tinmegali/mvp/mvp/ModelOps.java ================================================ package com.tinmegali.mvp.mvp; /** *

* Interface implemented by {@link GenericModel}.
* Contains * initializing and destruction methods called by VIEW layer in * all MVP objects. Garantes the correct synchronization of MVP * with Activity lifecycle. *

* IMPORTANT: View Object should implement RequiredViewOps *

* *

* Created by Tin Megali on 24/02/16.
* Project: AndroidMVP
* * www.tinmegali.com *

* ---------------------------------------------------
*

* Based on * framework MVP developed by * * Dr. Douglas Schmidth *

* * @see Project's Git
* @see Sample Application * @see * Sample MVP interface * * * * @param PRESENTER operations available to MODEL * Acts as a callback to data operations. */ public interface ModelOps { /** * Initialization method. Receives the PRESENTER reference. * Called by {@link GenericPresenter#initialize(Class, Object)} * * @param presenterOps PRESENTER reference, containing * operations available to MODEL */ void onCreate(RequiredPresenterOps presenterOps); /** * Hook method called when the VIEW is being destroyed or * having its configuration changed. * Responsible to maintain MVP synchronized with Activity lifecycle. * Called by {@link GenericPresenter#onDestroy(boolean)} * * @param isChangingConfiguration true: changing configuration * false: being destroyed */ void onDestroy(boolean isChangingConfiguration); } ================================================ FILE: AndroidMVP/mvp/src/main/java/com/tinmegali/mvp/mvp/PresenterOps.java ================================================ package com.tinmegali.mvp.mvp; /** *

* Interface implemented by {@link GenericPresenter}. Contains * initializing and destruction methods called by VIEW layer in * the PRESENTER. Garantes the correct synchronization of MVP * with Activity lifecycle. *

*

* IMPORTANT: View Object should implement RequiredViewOps *

* *

* Created by Tin Megali on 24/02/16.
* Project: AndroidMVP
* * www.tinmegali.com *

* ---------------------------------------------------
*

* Based on * framework MVP developed by * * Dr. Douglas Schmidth *

* @see Project's Git
* @see Sample Application * @see * Sample MVP interface * * * @param VIEW layer reference. Interface containing * operations available to PRESENTER * */ public interface PresenterOps extends ContextView { /** * Initialization method. * Called by initialization methods in VIEW, like * {@link GenericMVPActivity#initialize(Class, Object)} * {@link GenericMVPFragment#initialize(Class, Object)}. * Pass the VIEW reference with available operations to PRESENTER. * @param view Current VIEW instance reference, * with operations available */ void onCreate(RequiredViewOps view); /** * Hook method called every time the VIEW change its configuration. * Called by reinitialization methods in VIEW, like * {@link GenericMVPActivity#reinitialize(Class, Object)} * {@link GenericMVPFragment#reinitialize(Class, Object)} * Responsible to send a new reference to the VIEW layer with operations * available to PRESENTER. * * @param view New VIEW instance reference */ void onConfigurationChanged(RequiredViewOps view); /** * Hook method called when the VIEW is being destroyed or * having its configuration changed. * Responsible to maintain MVP synchronized with Activity lifecycle. * Called by onDestroy methods of the VIEW layer, like: * {@link GenericMVPActivity#onDestroy()} * {@link GenericMVPFragment#onDestroy()} * * @param isChangingConfiguration true: configuration changing * false: being destroyed */ void onDestroy(boolean isChangingConfiguration); /** * OnBack pressed Event, called by the VIEW. */ void onBackPressed(); } ================================================ FILE: AndroidMVP/mvp/src/main/java/com/tinmegali/mvp/mvp/StateMaintainer.java ================================================ package com.tinmegali.mvp.mvp; import android.app.Fragment; import android.app.FragmentManager; import android.os.Bundle; import android.util.Log; import java.lang.ref.WeakReference; import java.util.HashMap; /** * todo english comments *

Retains and maintain object's state between configuration changes * in Activitys and Fragments. *

*

* IMPORTANT: View Object should implement RequiredViewOps *

*

* Created by Tin Megali on 24/02/16.
* Project: AndroidMVP
* * www.tinmegali.com *

* ---------------------------------------------------
*

* Based on * framework MVP developed by * * Dr. Douglas Schmidth *

* * @see Project's Git
* @see Sample Application * @see * Sample MVP interface * */ public class StateMaintainer { protected final String TAG = getClass().getSimpleName(); private final String mStateMaintenerTag; private final WeakReference mFragmentManager; private StateMngFragment mStateMaintainerFrag; private boolean mIsRecreating; /** * Construtor * @param fragmentManager repassa uma referência do FragmentManager * @param stateMaintainerTAG a TAG utilizada para inserir o fragmento responsável * por manter os objetos "vivos" */ public StateMaintainer(FragmentManager fragmentManager, String stateMaintainerTAG) { mFragmentManager = new WeakReference<>(fragmentManager); mStateMaintenerTag = stateMaintainerTAG; } /** * cria o fragmento responsável por armazenar o objetos * @return true: criou o framentos e rodou pela primeira vez * false: o objeto já foi criado, portanto é apenas recuperado */ public boolean firstTimeIn() { try { // Recuperando referência mStateMaintainerFrag = (StateMngFragment) mFragmentManager.get().findFragmentByTag(mStateMaintenerTag); // Criando novo RetainedFragment if (mStateMaintainerFrag == null) { Log.d(TAG, "Criando novo RetainedFragment " + mStateMaintenerTag); mStateMaintainerFrag = new StateMngFragment(); mFragmentManager.get().beginTransaction() .add(mStateMaintainerFrag, mStateMaintenerTag).commit(); mIsRecreating = false; return true; } else { Log.d(TAG, "Retornando retained fragment existente " + mStateMaintenerTag); mIsRecreating = true; return false; } } catch (NullPointerException e) { Log.w(TAG, "Erro firstTimeIn()"); return false; } } /** * Return true it the current Activity was recreated at least one time * @return If the Activity was recreated */ public boolean wasRecreated() { return mIsRecreating; } /** * Insere objeto a serem presenrvados durante mudanças de configuração * @param key TAG de referência para recuperação do objeto * @param obj Objeto a ser mantido */ public void put(String key, Object obj) { mStateMaintainerFrag.put(key, obj); } /** * Insere objeto a serem presenrvados durante mudanças de configuração. * Utiliza a classe do Objeto como referência futura. * Só deve ser utilizado somente uma vez por classe, caso contrário haverá * possíveis conflitos na recuperação dos dados * @param obj Objeto a ser mantido */ public void put(Object obj) { put(obj.getClass().getName(), obj); } /** * Recupera o objeto salvo * @param key Chave de referência do obj * @param tipo genérico de retorno * @return Objeto armazenado */ @SuppressWarnings("unchecked") public T get(String key) { return mStateMaintainerFrag.get(key); } /** * Verifica a existência de um objeto com a chave fornecida * @param key Chave para verificação * @return true: obj existe * false: obj insexistente */ public boolean hasKey(String key) { return mStateMaintainerFrag.get(key) != null; } /** * Armazena e administra os objetos que devem ser preservados * durante mudanças de configuração. * É instanciado somente uma vez e utiliza um * HashMap para salvar os objetos e suas * chaves de referência. */ public static class StateMngFragment extends Fragment { private HashMap mData = new HashMap<>(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Garante que o Fragmento será preservado // durante mudanças de configuração setRetainInstance(true); } /** * Insere objetos no hashmap * @param key Chave de referência * @param obj Objeto a ser salvo */ public void put(String key, Object obj) { mData.put(key, obj); } /** * Insere objeto utilizando o nome da classe como referência * @param object Objeto a ser salvo */ public void put(Object object) { put(object.getClass().getName(), object); } /** * Recupera objeto salvo no hashmap * @param key Chave de referência * @param Classe * @return Objeto salvo */ @SuppressWarnings("unchecked") public T get(String key) { return (T) mData.get(key); } } } ================================================ FILE: AndroidMVP/mvp/src/main/java/com/tinmegali/mvp/mvp/package-info.java ================================================ /** *

* github.com/tinmegali/simple-mvp *

* * Provides the necessary classes to implement * a Model View Presenter architecture pattern. *

* Each layer of MVP pattern should extends * its generic object and implement the correct * interfaces to communicate with the other Layers.
* Check sample MVP interface * * sample interface * * *

    *
  • VIEW *
      *
    • * extends {@link com.tinmegali.mvp.mvp.GenericMVPActivity} or * {@link com.tinmegali.mvp.mvp.GenericMVPFragment} *
    • *
    • * implements RequiredViewOps: a interface that you create * containing VIEW operations * to be accessed by the PRESENTER *
    • *
    * *
  • *
  • * MODEL *
      *
    • * extends {@link com.tinmegali.mvp.mvp.GenericModel} *
    • *
    • * implements ProvidedModelOps: a interface that you create * containing MODEL operations * to be accessed by the PRESENTER *
    • * *
    * *
  • *
  • * PRESENTER *
      *
    • * extends {@link com.tinmegali.mvp.mvp.GenericPresenter} *
    • *
    • * implements RequiredPresenterOps: a interface that you create * containing PRESENTER operations * to be accessed by the VIEW *
    • *
    • * implements ProvidedPresenterOps: a interface that you create * containing PRESENTER operations * to be accessed by the MODEL *
    • *
    *
  • *
* * @see Project's Git
* @see Sample Application * @see * Sample MVP interface * * *

* Copyright 2016 Tin Megali 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. *

*

* Created by Tin Megali on 24/02/16.
* Project: AndroidMVP
* * www.tinmegali.com *

* ---------------------------------------------------
*

* Based on * framework MVP developed by * * Dr. Douglas Schmidth *

*/ package com.tinmegali.mvp.mvp; ================================================ FILE: AndroidMVP/mvp/src/main/java/com/tinmegali/mvp/util/ActivityKeyBoardDetector.java ================================================ package com.tinmegali.mvp.util; import android.graphics.Rect; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.view.ViewTreeObserver; import android.widget.Toast; /** * Created by Tin Megali on 24/02/16.
* Project: AndroidMVP
* * www.tinmegali.com
* Project's Git
* ---------------------------------------------------
*

* Object to add to an Activity the capability to detect the presence * of the SoftKeyboard.
* */ public abstract class ActivityKeyBoardDetector extends AppCompatActivity { private final String TAG = ActivityKeyBoardDetector.class.getSimpleName(); @Override protected void onDestroy() { // Remove LayoutChange listener stopDetectRootViewChanges(); super.onDestroy(); } /** * Shows a toast in the Activity with a short time * @param msg Message to show */ protected void showToast(String msg) { Toast.makeText( getApplicationContext(), msg, Toast.LENGTH_SHORT ).show(); } /** * Shows a android.widget.Toast in the Activity with custom time * @param msg Message to show * @param duration Time Length * android.widget.Toast#LENGTH_SHORT * @link android.widget.Toast#LENGTH_LONG */ protected void showToast(String msg, final int duration) { Toast.makeText( getApplicationContext(), msg, Toast.LENGTH_SHORT ).show(); } /** * Shows a Snackbar in Activity with a short time * @param msg Snackbar message * @param view Snackbar parent view */ protected void showSnackbar(String msg, View view){ android.support.design.widget.Snackbar.make(view, msg, android.support.design.widget.Snackbar.LENGTH_SHORT).show(); } /** * Shows a Snackbar in Activity with custom time * @param msg Snackbar message * @param view Snackbar parent view * @param duration Time Length * Snackbar#LENGTH_SHORT * Snackbar#LENGTH_LONG * Snackbar#LENGTH_INDEFINITE */ protected void showSnackbar(String msg, View view, int duration){ android.support.design.widget.Snackbar.make( view, msg, duration).show(); } /** * Shows a given Snackbar * Useful for snacks with custom actions. * @param snackbar The Snackbar to show */ protected void showSnackbar(android.support.design.widget.Snackbar snackbar){ snackbar.show(); } /** * Detecting Layout Root changes *
    *
  • {@link #startDetectRootViewChanges(View)} must be called on {@link #onCreate(Bundle)}
  • *
  • Detect if SoftKeyboard is On/Off * {@link #onKeyBoardOn()} {@link #onKeyBoardOff()}
  • *
  • Register event for layout changes * {@link #onRootLayoutChanged(int)}
  • *
*/ private View mActivityRootView; private ViewTreeObserver.OnGlobalLayoutListener mLayoutListener; /** * Create a new Global Layout Listener */ private ViewTreeObserver.OnGlobalLayoutListener createLayoutListener() { Log.d(TAG, "createLayoutListener"); final int KEYBOARD_GREATER_THAN = 125; return new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { Rect rect = new Rect(); mActivityRootView.getWindowVisibleDisplayFrame(rect); int heightDiff = mActivityRootView.getHeight() - (rect.bottom - rect.top); if (heightDiff>0) onRootLayoutChanged(heightDiff); if (heightDiff > KEYBOARD_GREATER_THAN) { // if more than 100 pixels, its probably a keyboard... Log.d(TAG, "onGlobalLayout(). Probabaly a keyBoard. > heightDiff[" + heightDiff + "]"); onKeyBoardOn(); mIsKeyboardOn = true; } else { if (mIsKeyboardOn) { onKeyBoardOff(); mIsKeyboardOn = false; } } } }; } /** * Start to detect changed on Root layout height * - Register a Root view * - Create and starts a Global Layout Listener * - Register root view layout events * {@link #onKeyBoardOn()} * {@link #onKeyBoardOff()} * {@link #onRootLayoutChanged(int)} * @param activityRootView Root layout to be monitored */ protected void startDetectRootViewChanges(final View activityRootView) { Log.d(TAG, "startDetectRootViewChanges()"); mActivityRootView = activityRootView; mIsKeyboardOn = false; mLayoutListener = createLayoutListener(); mActivityRootView.getViewTreeObserver().addOnGlobalLayoutListener(mLayoutListener); } /** * Remove Global Layout change listener */ protected void stopDetectRootViewChanges() { Log.d(TAG, "stopDetectRootViewChanges()"); if ( mActivityRootView != null ) mActivityRootView.getViewTreeObserver().removeOnGlobalLayoutListener(mLayoutListener); } private Boolean mIsKeyboardOn; /** * Controls if SoftKeyBoard is on/off * - May return null if {@link #startDetectRootViewChanges(View)} wasn't called * @return true if SoftKeyboard is showing on screen */ protected Boolean isKeyboardOn() { Log.d(TAG, "isKeyboardOn()"); return mIsKeyboardOn; } /** * Called on SoftKeyBoard is ON * - Depends on {@link #startDetectRootViewChanges(View)} * - It must be called more than one time */ protected void onKeyBoardOn() { Log.d(TAG, "onKeyBoardOn()"); } /** * Called on SoftKeyBoard is OFF * - Depends on {@link #startDetectRootViewChanges(View)} * - It must be called more than one time */ protected synchronized void onKeyBoardOff() { Log.d(TAG, "onKeyBoardOff()"); } /** * Called when Root Layout view changes * - Depends on {@link #startDetectRootViewChanges(View)} * @param heightDiff Height Difference between current * Root View an available Windo size */ protected void onRootLayoutChanged(int heightDiff) { Log.d(TAG, "onRootLayoutChanged(heightDiff[" + heightDiff + "])"); } } ================================================ FILE: AndroidMVP/mvp/src/main/res/values/AndroidManifest.xml ================================================ ================================================ FILE: AndroidMVP/mvp/src/main/res/values/strings.xml ================================================ MVP ================================================ FILE: AndroidMVP/settings.gradle ================================================ include ':app', ':mvp' ================================================ FILE: README.md ================================================

Android-Model-View-Presenter-MVP

A Model View Presenter Library using plain and simple interfaces, based on concept from Dr. Douglas Schmidt

Attention: simple-mvp is still an experimental library created for education purposes.
Some methods and operations may change until its maturity.

Created by Tin Megali

Learn more

Quick install

  1. add build.gradle
    compile 'com.tinmegali.mvp:mvp:0.0.7'
  2. Create interfaces to communicate between MVP layers
    • interface RequiredViewOps extends ActivityView
      with VIEW methods to be accessed by PRESENTER
    • interface ProvidedPresenterOps extends PresenterOps
      Operations offered to VIEW to communicate with PRESENTER
    • interface RequiredPresenterOps
      with Required PRESENTER methods available to MODEL
    • interface ProvidedModelOps extends ModelOps
      Operations offered to MODEL to communicate with PRESENTER
  3. Implement MVP objects extending its generics
    • MODEL from Model View Presenter (MVP) pattern.
      class MODEL extends GenericModel implements MVP_MainActivity.ProvidedModelOps
    • VIEW layer of MVP pattern
      class VIEW_Activity extends GenericMVPActivity implements MVP_MainActivity.RequiredViewOps
      Could also extend GenericMVPFragment
    • PRESENTER from Model View Presenter (MVP) Pattern.
      class MainPresenter extends GenericPresenter implements MVP_MainActivity.RequiredPresenterOps, MVP_MainActivity.ProvidedPresenterOps

Instalação rápida

  • Crie as interfaces de comunicação entre os módulos View, Presenter e Model
    1. interface RequiredViewOps fornece métodos para Presenter comunicar com View. É necessário extender ActivityView
    2. interface ProvidedPresenterOps fornece operações oferecidas ao layer View para comunicação com Presenter. É preciso extender PresenterOps
    3. interface RequiredPresenterOps operações oferecidas pelo layer Presenter para comunicações com Model
    4. interface ProvidedModelOps operações oferecidos pelo layer Model para comunicações com Presenter. É preciso extender ModelOps
  • Crie a classe Model extendendo GenericModel e implementando ProvidedModelOps ex: {@link com.tinmegali.androidmvp.main.model.MainModel}
  • Crie a classe Presenter extendendo GenericPresenter, implementando RequiredPresenterOps e ProvidedPresenterOps. exemplo: {@link com.tinmegali.androidmvp.main.presenter.MainPresenter}
  • Crie a classe View GenericMVPActivity ou GenericMVPFragment e implementando RequiredViewOps Exemplo: {@link com.tinmegali.androidmvp.main.view.MainActivity}
  • .

Android MVP Class Diagram