Android 基本架构之MVP分析与实践

开发一个App,和起房子应该有殊途同归之处,起房子须要画好设计图纸,而咱们开发App则须要先设计好App整个架构模式。目前Android通常有MVC、MVP和MVVM,本文则先来讲说MVP架构。在了解MVP架构以前,有人可能会说,MVP架构是否是有点落后了,可是我想说,若是你公司有老项目,他就是用MVP架构写的,这时候咱们MVP知识是否是就派上用场了;任何架构都有它存在的理由,学习架构的思想才是关键。MVP分别表明Model、View、Presenter三个英文字母,和传统的MVC 相比,C替换成了P。Presenter英文单词有主持人意思,也就是说Presenter是View 和 Model 的主持人,按照惯例咱们先来看两张图。android

MVC MVP 架构对比图

mvc

mvc

mvp

mvp

  • 经过以上两张图对比,MVC在Android中就是咱们刚开始学习Android时输出Android代码的真实写照,Activity不只负责显示View,它仍是Controller,咱们能够在Activity开始网络请求,请求完成更新UI,也能够在Activity中经过UI组件获取用户输入数据,而后执行网络请求再更新UI,这样一来,一个功能复杂的页面一个Activity三四千行代码是很常见的事情,这也会致使后面维护代码人来读你的Activity代码可能会直接崩溃,同时代码的耦合度也很高。
  • 而咱们再看MVP架构,这就会很清晰,它把MVC中的VC进行解耦,也就是说把Activity中的UI逻辑抽象成View 接口 ,把业务逻辑抽象成 presenter 接口, model 仍是原来的model,这样其实就呼应了文章咱们所说presenter主持人的意思,model 更新UI须要经过presenter,view 更新model数据也须要经过presenter,至关于presenter主持大局。
  • 说了这么多,其实MVC和MVP的区别能够用一句话代替,那就是View可否直接操做Model,接下来咱们就看看MVP架构如何在Android中实践。

Android 实现 mvp 架构

UI逻辑抽象成View接口

/**
 * @author maoqitian
 * @Description View 的基类
 */
public interface BaseView {

    /**
     * 正常显示
     */
    void showNormal();

    /**
     * 显示错误
     */
    void showError();

    /**
     * 正在加载
     */
    void showLoading();
    /**
     * 显示错误信息
     * @param errorMsg 错误信息
     */
    void showErrorMsg(String errorMsg);
}
复制代码

业务逻辑抽象成 Presenter 接口

  • 抽象以前咱们能够想想,每一个presenter都对应一个View 界面,因此咱们须要一个方法来绑定对应的View,绑定的目的是为了方便咱们在presenter中更新view,当界面销毁的时候也须要一个方法类解绑View。此外,界面确定不止一个,而且确定实现前面咱们写的BaseView接口,咱们用泛型代替,就有了以下BasePresenter 接口
/**
 * @author maoqitian
 * @Description Presenter 基类接口
 */
public interface AbstractBasePresenter<T extends BaseView> {

    /**
     * 绑定View
     * @param view
     */
    void attachView(T view);

    /**
     * 解绑View
     */
    void detachView();
}
复制代码

MVP工做流

  • 前面咱们已经抽象出了View、Presenter接口,接下来从结合文章开头MVP architectural pattern图从用户打开App获取数据开始展示总体MVP工做流。

View 与 Presenter 结合

View 获取Presenter对象

  • View 获取数据须要经过Presenter对象,view在Android 中通常表明Avtivity、或者Fragment。先建立Avtivity和Fragment抽象类类作基础封装。
/**
 * @author maoqitian
 * @Description activity基类
 */
public abstract class AbstractActivity extends AppCompatActivity{

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayout());
        onViewCreated();
        initToolbar();
        initEventAndData();
    }
    /**
     * view 的建立 留给子类实现
     */
    protected abstract void onViewCreated();
    /**
     * 初始化 toolbar
     */
    protected abstract void initToolbar();
    /**
     * 初始化数据留给子类实现
     */
    protected abstract void initEventAndData();

    /**
     * 获取布局对象 留给子类实现
     */
    protected abstract int getLayout();

}
复制代码
  • 接着咱们实现MVP Activity基类
/**
 * @author maoqitian
 * @Description MVP BaseActivity 基类
 */
public abstract class  BaseActivity <T extends AbstractBasePresenter> extends AbstractActivity implements BaseView{

    protected T mPresenter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        mPresenter = createPresenter();
        super.onCreate(savedInstanceState);
        
    }

    @Override
    protected void onViewCreated() {
        if (mPresenter != null) {
            mPresenter.attachView(this);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(mPresenter != null){
            mPresenter.detachView();
            mPresenter = null;
        }
    }

    /**
     * 建立Presenter
     */
    protected abstract T createPresenter();

    @Override
    public void showNormal() {

    }

    @Override
    public void showError() {

    }

    @Override
    public void showLoading() {

    }

    @Override
    public void showErrorMsg(String errorMsg) {

    }
}    
复制代码
  • 到此,只要咱们界面继承BaseActivity,而且实现createPresenter方法,咱们就能够很直接在View中经过Presenter来获获取数据,如何获取呢?接着往下看。

Presenter 获取View 对象

  • 如今咱们建立一个Presenter基类将其与View结合,为后续步骤作准备,注意咱们RxBasePresenter基类构造方法中须要传入DataClient,该类其实就能够归纳表明Module。
/**
 * @author maoqitian
 * @Description 基于Presenter封装 
 */
public class RxBasePresenter<T extends BaseView> implements AbstractBasePresenter<T>{

    protected T mView;
    
    private DataClient mDataClient;


    public RxBasePresenter(DataClient dataClient){
        this.mDataClient=dataClient;
    }

    @Override
    public void attachView(T view) {
       this.mView=view;
    }

    @Override
    public void detachView() {
        this.mView = null;
    }
}
复制代码

Presenter 与 View 之间链接

  • 当咱们建立View 对应Presenter让其继承 RxBasePresenter,则 Presenter即可以执行Updates view,如何操做呢?咱们能够经过接口来进行数据获取与显示的扩展。如下举个例子
public interface MainContract {

    interface MainView extends BaseView{
        void showMainData();
    }


    interface MainActivityPresenter extends AbstractBasePresenter<MainView>{
        void getMainData();
    }
}
复制代码
  • 至此,咱们基本MVP架构其实就已经搭建完成,咱们来看看使用
/**
 * @author maoqitian
 * @Description MainPresenter (Presenter)
 */
public class MainPresenter extends RxBasePresenter<MainContract.MainView> implements MainContract.MainActivityPresenter {

    //(Model)
    private DataClient mDataClient;

    public MainPresenter(DataClient dataClient) {
        super(dataClient);
        this.mDataClient = dataClient;
    }
    @Override
    public void attachView(MainContract.MainView view) {
        super.attachView(view);
        
    }
    //获取数据
    @Override
    public void getMainData() {
        //mDataClient 网络请求获取数据
        .......
        // 数据获取成功展现数据
        mView.showMainData();
    }
}
/**
 * @author maoqitian
 * @Description MainActivity (View)
 */
public class MainActivity extends BaseActivity<MainPresenter>implements MainContract.MainView{
    ..........
    @Override
    protected MainPresenter createPresenter() {
        return new MainPresenter(new DataClient());
    }
    
    @Override
    protected void initEventAndData() {
        mPresenter.getMainData();
    }
    
    @Override
    public void showMainData() {
    //显示数据
    }   
    
}
复制代码
  • 经过以上示例代码,再次对比文章开头的Android MVP architectural pattern图,从用户打开App获取数据开始展示总体MVP工做流已经走完。

谷歌官方示例MVP demo

  • 固然上面只是简单的讲解了在Android中搭建基本MVP架构,其实谷歌官方也给我提供了MVP示例代码,具体代码能够自行去了解。
  • 谷歌官方MVP示例Demo

使用dagger2优化MVP 架构

  • 前面咱们大体搭建了一个基础的MVP架构,每一个Presnter须要咱们在View 中去建立,建立Presnter的时候还须要传入Model,这就说明他们之间的解耦还不够。这里咱们换一种思路,在原有基础,不论是DataClient(Model)仍是对应的Presnter均可以直接提供对应的对象,而后对应的类建立咱们就将其注入,这样不就省去了对象建立,Model、Presnter、View 之间耦合度就进一步下降,如何实现?仍是强大的谷歌爸爸给咱们提供了方案,使用Dagger2(Dagger是一个彻底静态的编译时依赖注入框架,适用于Java和Android)。

项目添加对应dagger依赖

  • 使用dagger对应版本为2.22.1
dependencies {
  implementation 'com.google.dagger:dagger:2.22.1'
  annotationProcessor 'com.google.dagger:dagger-compiler:2.22.1'
  //
  implementation 'com.google.dagger:dagger-android:2.22.1'
  implementation 'com.google.dagger:dagger-android-support:2.22.1'
  annotationProcessor 'com.google.dagger:dagger-android-processor:2.22.1'
}
复制代码

改造Presnter类

  • 这里咱们以上面例子中MainPresenter为例,在其构造方法添加@Inject注解,代表Dagger2 能够从这获取对应MainPresenter实例,注意构造方法中须要DataClient对象,这里也使用Dagger来提供对象(稍后再说)
public class MainPresenter extends RxBasePresenter<MainContract.MainView> implements MainContract.MainActivityPresenter {

    private DataClient mDataClient;
    //@Inject注解表示Dagger2 能够从这获取Presenter 实例
    @Inject 
    public MainPresenter(DataClient dataClient) {
        super(dataClient);
        this.mDataClient = dataClient;
    }
}
复制代码

改造View

  • View 中结合 Dagger2 本应该继承 DaggerAppCompatActivity,可是咱们基类为AbstractActivity,查看DaggerAppCompatActivity源码,直接手动实现DaggerAppCompatActivity中代码。
/**
 * @author maoqitian
 * @Description MVP BaseActivity 基类
 */
public abstract class  BaseActivity <T extends AbstractBasePresenter> extends AbstractSimpleActivity implements BaseView, HasFragmentInjector,HasSupportFragmentInjector {

    //Presenter 对象注入 (注意不能使用 private )
    @Inject
    protected T mPresenter;
    //手动实现DaggerAppCompatActivity功能
    @Inject DispatchingAndroidInjector<Fragment> supportFragmentInjector;
    @Inject DispatchingAndroidInjector<android.app.Fragment> frameworkFragmentInjector;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        //必须在super.onCreate以前调用AndroidInjection.inject
        AndroidInjection.inject(this);
        super.onCreate(savedInstanceState);
    }
     @Override
    public AndroidInjector<Fragment> supportFragmentInjector() {
        return supportFragmentInjector;
    }

    @Override
    public AndroidInjector<android.app.Fragment> fragmentInjector() {
        return frameworkFragmentInjector;
    }
}    
复制代码

添加Dagger Module和Component

建立MainActivityModule

  • 抽象类MainActivityModule加入@Module注解,并添加返回咱们对应MainActivityPresenter接口的抽象方法,@Binds注解就能够帮咱们把MainActivityPresenter接口绑定到MainPresenter上。
/**
 * @author maoqitian
 * @Description MainActivity 能够提供的注入对象Module
 * @Time 2019/3/27 0027 23:59
 */
@Module
public abstract class MainActivityModule {
    @ActivityScope
    @Binds
    abstract MainContract.MainActivityPresenter bindPresenter(MainPresenter presenter);
}
复制代码

建立用于生成Activity注入器的Module类

/**
 * @author maoqitian
 * @Description 用于生成Activity注入器的Module,使用@ContributesAndroidInjector注解并指定modules为
 * @Time 2019/4/14 0014 14:09
 */
@Module
public abstract class ActivityBindingModule {
   
    @ActivityScope
    @ContributesAndroidInjector(modules = MainActivityModule.class)
    abstract MainActivity contributeMainActivity();
    
}
复制代码

建立提供咱们须要对象的Module类

  • 与前文对应,这里咱们提供了对应了DataClient对象,也就是MVP中的Model,在注入Presenter的时候将其一块儿注入。
@Module
public class MyAppModule {

    @Provides
    @Singleton
    public DataClient providerDataClient(){
        return new DataClient();
    }
}

复制代码

使用@Component注解建立AppCompontent接口类

  • Dagger会帮咱们自动生成DaggerAppComponent类,继承自AndroidInjector并指定咱们本身的Application类,指定AndroidSupportInjectionModule帮助把Android中四大组件以及Fragment进行绑定,@Singleton注解指定单例
@Singleton
@Component(modules = {
        MyAppModule.class,
        ActivityBindingModule.class,
        AndroidSupportInjectionModule.class
})
public interface AppComponent extends AndroidInjector<MyApplication> {
}
复制代码

改造Application类继承自DaggerApplication

  • 按照以下改造MyApplication以后咱们重新编译编译一下代码,若是编译经过,dagger就会帮咱们生成对应DaggerAppComponent.create()方法,将其返回在applicationInjector()方法中。
public class MyApplication extends DaggerApplication {
     @Override
    protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
        return DaggerAppComponent.create();
    }
}
复制代码
  • 项目编译经过dagger会在build目录生成对应对象注入类,具体源码之后再出文章分析,这里就先告一段落了。到此,使用dagger2优化MVP 架构基本完成了,可是还有其余细节这里没有说起,好比每一个Presenter之间该如何通讯,可使用EventBus,也能够Rxbus等等,具体细节能够看接下架构实践中我写的开源项目的代码。

架构实践

项目介绍

  • 经过前面对MVP架构分析介绍,接下来我给你们推荐个人一个开源项目,这是一款有较好用户体验的开源玩Android客户端。提供丰富完整的功能,更好的体验,旨在更好的浏览https://www.wanandroid.com/网站内容,更好的在手机上进行学习。项目使用Retrofit2 + RxJava2 + Dagger2 +MVP+RxBus架构,尽可能使用Material Design控件进行开发。

项目架构图

MVP-WanAndroid-Architecture

项目地址

github.com/maoqitian/M…git

总结

  • 之前所说的知识一种MVP架构的写法,咱们也能够根据本身理解写出不同的MVP,其实MVP架构看似不错,但也仍是会有缺点,那就是写一个页面会产生不少个类,虽然结构清晰,可是要写的代码变多了,凡事都会有利弊。若是你不想本身写这么多的类,github上也有大神写好了轮子(MVPArms)专门帮咱们生成MVP架构的框架,可是用框架生成代码总归是别人的,只有本身撸一遍,把逻辑流程梳理清楚才会变成本身的东西,才会成长。文章中若是有错误,请你们给我提出来,你们一块儿学习进步,若是以为个人文章给予你帮助,也请给我一个喜欢和关注,同时也欢迎访问个人我的博客

About me

blog:

mail:

相关文章
相关标签/搜索