I. Preface
This article is a summary of my past app development and a reflection on the use of the framework. I also invite you to laugh at the technical salted fish. Generally speaking, the first thing we think about when we develop app is how to build a framework. At first, there was no so-called framework in app development. There were so-called frameworks when more people wrote. At present, all the frameworks on the market are MVC, MVP and MVVM. The so-called MVC framework is the most primitive app development, ui layout processing, network data processing, business code logic processing are rubbed in an Activity to make the whole class extremely bloated. Neither the subsequent expansion nor maintenance is as painful as eggs, which is the most unacceptable. MVVM uses data binding, a control data binding framework criticized by many people around me, so I finally chose the MVP framework, better gossip less into the topic.
Encapsulation
Here I will explain the principle of MVP. Here I will mainly talk about my personal views on the use and encapsulation of MVP.
Let's first create the View layer, the base class of Presenter layer. It's important to mention that no matter the object using the View layer in the p layer is not used directly, but is invoked through a method medium.
/** * * 2018/5/24 * Create by GeenFour * @param <V> */ public abstract class BasePresenter<V extends BaseMvpView> extends ViewModel implements BaseMvpPresenter<V>,OnHttpCallBackListener { private CompositeDisposable compositeDisposable; //Preventing Rx Java Memory Leakage private V view; protected BasePresenter(V view){ this.view =view; compositeDisposable = new CompositeDisposable(); } protected V getMvpView(){ return view; } /** * * @param observable * @param what * @param <T> */ public <T> void domine(Observable<T> observable, final int what){ //The combination of RxJava+Retrofit is used in network processing to obtain network data by callback. The advantage of this method is that the processing of the result of the request or the exception of the request can be set globally or individually with high flexibility. observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<T>() { @Override public void onSubscribe(@NonNull Disposable d) { compositeDisposable.add(d); } @Override public void onNext(@NonNull T t) { onResponse(t,what); } @Override public void onError(@NonNull Throwable e) { onErrors(e,what); } @Override public void onComplete() { onCompletes(what); } }); } @Override public void onCreate(LifecycleOwner owner) { } @Override public void onDestory(LifecycleOwner owner) { if(compositeDisposable!=null){ compositeDisposable.clear(); } } @Override public void onPause(LifecycleOwner owner) { } @Override public void onAny(LifecycleOwner owner) { } @Override public void onResume(LifecycleOwner owner) { } @Override public void onStop(LifecycleOwner owner) { } @Override public void onStart(LifecycleOwner owner) { } @Override public void onErrors(Throwable e, int what) { Toast.show("Please check the network connection"); } @Override public void onCompletes(int what) { } }
Binding Presenter's life cycle with lifecycle avoids closing the View layer (Activity/Fragment) while the P layer is still in the network request, and calling the View layer method to report the null pointer exception when the network request ends. The BaseMVPVIew here is just an empty interface class, which I haven't talked about much here.
/** * 2018/5/24 * Create by GeenFour * @param <V> */ public interface BaseMvpPresenter<V extends BaseMvpView> extends LifecycleObserver{ @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) void onCreate(LifecycleOwner owner); @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) void onPause(LifecycleOwner owner); @OnLifecycleEvent(Lifecycle.Event.ON_ANY) void onAny(LifecycleOwner owner); @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) void onDestory(LifecycleOwner owner); @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) void onResume(LifecycleOwner owner); @OnLifecycleEvent(Lifecycle.Event.ON_STOP) void onStop(LifecycleOwner owner); @OnLifecycleEvent(Lifecycle.Event.ON_START) void onStart(LifecycleOwner owner); }
Build Presenter's interface class for interaction at the View layer.
For View layer encapsulation, this layer encapsulation is only one encapsulation for MVP framework.
/** * * * BaseClass for Activity * Create by GeenFour * 2018 5/23 */ public abstract class BaseFrameActivity<P extends BaseMvpPresenter> extends AppCompatActivity { private P presenter; /** * * @param savedInstanceState */ @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); initDagger(); presenter = createPresenter(); getLifecycle().addObserver(presenter); } protected abstract void initDagger(); /** * * @param outState */ @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); } /** * * @return */ @NonNull protected abstract P createPresenter(); protected P getPresenter(){ return presenter; } }
For the second encapsulation of View layer, this layer is the encapsulation of functions. With Icepick and RxBus, some students who are interested in dealing with it can go to extra research.
/** * * Create by GeenFour * @param <P> */ public abstract class BaseActivity<P extends BaseMvpPresenter> extends BaseFrameActivity<P> implements BaseMvpView{ private Context context; private Intent intent; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { Window window = getWindow(); window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); // window.setStatusBarColor(0xFFFFFFFF); } JFInject.regist().bind(this); AppManager.getAppManager().addActivity(this); Icepick.restoreInstanceState(this,savedInstanceState); init(); } /** * * get context instance * @return */ protected Context getContext(){ if(context==null){ context = this; } return context; } /** * * @param clazz */ protected Intent openActivity(@Nullable Class clazz){ intent = new Intent(getContext(),clazz); return intent; } /** * * * @param clazz * @param obj */ protected void openActivity(@Nullable Class clazz,@Nullable Object obj){ RxBus.getInstance().postSticky(obj); startActivity(openActivity(clazz)); } @Override public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) { super.onSaveInstanceState(outState, outPersistentState); Icepick.saveInstanceState(this,outState); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); Icepick.saveInstanceState(this,outState); } /** * * initialization setting */ protected abstract void init(); @Override protected void onDestroy() { super.onDestroy(); context =null; JFInject.finish(); RxBus.getInstance().removeAllStickyEvents(); } }
Three, use
Actual use, View layer here
@ContentView(R.layout.activity_test) public class TestActivity extends BaseActivity<TestContract.TestPresenter> implements TestContract.TestView { @Inject TestPresenterImpl presenter; @BindId(R.id.tv_content) TextView mTvContent; @BindId(R.id.fl_content) FrameLayout frameLayout; private TestViewModel model; @Override protected void init() { //Calling P-tier methods getPresenter().testPresenter(); model = ViewModelProviders.of(this).get(TestViewModel.class); model.getStudentMutableLiveData().observe(this,s ->{ Toast.show(s); mTvContent.setText(s); }); FragmentManager manager = getSupportFragmentManager(); FragmentTransaction transaction = manager.beginTransaction(); TestFragment testFragment = new TestFragment(); transaction.add(R.id.fl_content,testFragment); transaction.commit(); } @OnClick({R.id.tv_content}) public void click(View view){ switch (view.getId()){ case R.id.tv_content: model.changeName("lalala"); break; } } @Override protected void initDagger() { DaggerTestContract_TestDaggerComponent.builder().testModule(new TestModule(this)).build().inject(this); } @NonNull @Override protected TestContract.TestPresenter createPresenter() { return presenter; } @Override public void testView(String string) { Toast.show(string); } }
Presenter level
public class TestPresenterImpl extends BasePresenter<TestContract.TestView> implements TestContract.TestPresenter{ @Inject public TestPresenterImpl(TestContract.TestView view) { super(view); } //This is the place to get the network data callback @Override public void onResponse(Object object, int what) { switch(what){ case: ResponseBody requestBody = (ResponseBody) object; break; } } @Override public void testPresenter() { //getMvpView().testView("PRESENTER"); //This is the call of the network request. domine(RetrofitUntils.getService().jokes(ApiConfig.KEY,1,15,"asc","1418816972"),0); } }
I aggregate all the interface classes for MVP in one class, which can greatly reduce the number of classes.
public class TestContract { interface TestView extends BaseMvpView{ void testView(String string); } interface TestPresenter extends BaseMvpPresenter<TestView>{ void testPresenter(); } @Component(modules = TestModule.class) public interface TestDaggerComponent { void inject(TestActivity activity); } }
Module class to be used by Daager2
@Module public class TestModule { private TestContract.TestView view; public TestModule(TestContract.TestView view){ this.view = view; } @Provides public TestContract.TestView getTestContractView(){ return view; } }
By the way, the previous Presenter layer was an inherited ViewModel class
I don't use it here in Presenter, but in another class to make it look clearer.
/** * * Data Sharing for Activity and Fragment */ public class TestViewModel extends ViewModel{ private MutableLiveData<String> studentMutableLiveData =new MutableLiveData<>(); public void changeName(String name) { studentMutableLiveData.setValue(name); } public MutableLiveData<String> getStudentMutableLiveData() { return studentMutableLiveData; } }
This article is just a brief introduction to a simple package of MVP. The details are in the code. Later, I will integrate these into a basic framework and upload them to Jcenter. Welcome your different opinions and suggestions.