MVP Framework of RxJava+retrofit+Dagger2+AAC

Keywords: network Fragment less Java

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.

Posted by lordofgore on Sat, 22 Dec 2018 07:06:05 -0800