从零开始搭建一个主流项目框架(二)—MVP+dagger2

个人博客:haichenyi.com。感谢关注

  接着上一篇简单的框架,没有看过的同鞋可以去喵一眼。上一篇我们搭好了简单的框架,初始化一次的内容丢在Application里面,所有的activity继承一个类BaseActivity,还有Fragment继承的一个类BaseFragment

  现在我们来加上MVP,不懂MVP的同鞋可以看一下,我前面写过的三种主流框架的对比。我们先导入dagger2的两个包,代码如下:

implementation 'com.google.dagger:dagger:2.14.1'
annotationProcessor "com.google.dagger:dagger-compiler:2.14.1"

第一步

  新建BasePresenter接口,BaseMvpPresenter类去实现BasePresenter接口,代码如下

package com.shfzwkeji.smartwardrobe.base;

/**
 * Author: 海晨忆.
 * Date: 2017/12/21
 * Desc: 不带mvp的presenter的基类
 */
public interface BasePresenter<T extends BaseView> {
  void attachView(T baseView);

  void detachView();
}
package com.haichenyi.myproject.base;

/**
 * Author: 海晨忆
 * Date: 2018/2/23
 * Desc:带mvp的presenter的基类
 */
public class BaseMvpPresenter<T extends BaseView> implements BasePresenter<T> {
  protected T baseView;

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

  @Override
  public void detachView() {
    this.baseView = null;
  }
}

  这里就只有两个方法,一个是绑定view,还有一个是在ondestory方法里面解除绑定的方法,用来保证P层的生命周期和V层同步,避免了,当V层销毁的时候,P层仍然存在造成的内存泄漏。

第二步

  新建BaseMvpActivity

package com.haichenyi.myproject.base;

import javax.inject.Inject;

/**
 * Author: 海晨忆
 * Date: 2018/2/23
 * Desc:带MVP的Activity
 */
public abstract class BaseMvpActivity<T extends BasePresenter>  extends BaseActivity{
  @Inject
  protected T basePresenter;

  @Override
  @SuppressWarnings("unchecked")
  protected void initView() {
    super.initView();
    initInject();
    if (null != basePresenter) {
      basePresenter.attachView(this);
    }
  }

  protected abstract void initInject();

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

  运用dagger2注解的方式,生成P层,这里我们在用P层之前得先生成P层,所以initject方法一定要在basePresenter用之前调用,因为他就是生成P层的代码。

  怎么生成呢?dagger我们一般都命名成di层,所以,我们先创建di层的package,项目结构图如下:

《从零开始搭建一个主流项目框架(二)—MVP+dagger2》 项目结构图.png

  这里给出的是mvp+dagger加入之后的项目结构。我们重点看选中的di层,里面有4个package分别是component,module,qualifier,scope四个包,至于他们的作用分别是什么,请自行百度,google,dagger的用法。我这里先贴出这几个类,接口的代码:

ActivityComponent

package com.haichenyi.myproject.di.component;

import com.haichenyi.myproject.MainActivity;
import com.haichenyi.myproject.di.module.ActivityModule;
import com.haichenyi.myproject.di.scope.ActivityScope;

import dagger.Component;

/**
 * Author: 海晨忆
 * Date: 2018/2/23
 * Desc:
 */
@ActivityScope
@Component(dependencies = AppComponent.class, modules = ActivityModule.class)
public interface ActivityComponent {
  void inject(MainActivity mainActivity);
}

AppComponent

package com.haichenyi.myproject.di.component;

import com.haichenyi.myproject.di.module.AppModule;
import com.haichenyi.myproject.di.module.HttpModule;

import javax.inject.Singleton;

import dagger.Component;

/**
 * Author: 海晨忆
 * Date: 2018/2/23
 * Desc:
 */
@Singleton
@Component(modules = {AppModule.class, HttpModule.class})
public interface AppComponent {
}

ActivityModule

package com.haichenyi.myproject.di.module;

import dagger.Module;

/**
 * Author: 海晨忆
 * Date: 2018/2/23
 * Desc:
 */
@Module
public class ActivityModule {
}

AppModule

package com.haichenyi.myproject.di.module;

import com.haichenyi.myproject.base.MyApplication;

import dagger.Module;

/**
 * Author: 海晨忆
 * Date: 2018/2/23
 * Desc:
 */
@Module
public class AppModule {
  private MyApplication application;

  public AppModule(MyApplication application) {
    this.application = application;
  }
}

HttpModule

package com.haichenyi.myproject.di.module;

import dagger.Module;

/**
 * Author: 海晨忆
 * Date: 2018/2/23
 * Desc:
 */
@Module
public class HttpModule {
}

ActivityScope

package com.haichenyi.myproject.di.scope;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import javax.inject.Scope;

/**
 * Author: 海晨忆
 * Date: 2018/2/23
 * Desc:
 */
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScope {
}

  这几个类,接口里面基本上都没有内容,因为这几个类都是后面才会用的到的,这里我直接贴出来,说起来方便一些。还需要加两个方法,在MyApplication里面加如下方法:

/**
   * 获取AppComponent.
   *
   * @return AppComponent
   */
  public static synchronized AppComponent getAppComponent() {
    if (null == appComponent) {
      appComponent = DaggerAppComponent.builder()
          .appModule(new AppModule(getInstance()))
          .httpModule(new HttpModule())
          .build();
    }
    return appComponent;
  }

在BaseActivity里面加如下方法:

protected ActivityComponent getActivityComponent() {
    return DaggerActivityComponent.builder()
        .appComponent(MyApplication.getAppComponent())
        .activityModule(new ActivityModule())
        .build();
  }

  加完这两个方法之后,肯定会有错误提示,重新编译一遍项目就可以了,如果重新编译一遍,还是不行,请重新对比一下,哪里不一样。

第三步

  就是关于mvp的了,从上面图应该看到了,有一个presenter包,和contract包,我们之前有一篇博客讲过,MVP就是多了很多个接口,这些接口写在哪呢?就在contract层

MainContract 代码如下:

package com.haichenyi.myproject.contract;

import com.haichenyi.myproject.base.BasePresenter;
import com.haichenyi.myproject.base.BaseView;

/**
 * Author: 海晨忆
 * Date: 2018/2/23
 * Desc:
 */
public interface MainContract {
  interface IView extends BaseView{

  }
  interface Presenter extends BasePresenter<IView>{
    void loadData();
  }
}

  这里我需要说明的就是Presenter接口继承的是IVew,不是BaseView,页面变化的方法都是在IView接口里面定义,逻辑处理,网络请求方法都是在Presenter接口里面定义

MainPresenter 代码如下

package com.haichenyi.myproject.presenter;

import com.haichenyi.myproject.base.BaseMvpPresenter;
import com.haichenyi.myproject.contract.MainContract;

import javax.inject.Inject;

/**
 * Author: 海晨忆
 * Date: 2018/2/23
 * Desc:
 */
public class MainPresenter extends BaseMvpPresenter<MainContract.IView>
    implements MainContract.Presenter {
  @Inject
  MainPresenter() {
  }

  @Override
  public void loadData() {
    baseView.showTipMsg("加载数据");
  }
}

  这里我需要说明的是注意继承BaseMvpPresenter传的是MainContract.IView,不是BaseView,实现MainContract.Presenter接口,还有一点就是注意构造方法,上面有注解,这里的loadData里面应该是我们的网络请求逻辑,这里我放到后面一篇在说,这里我先就直接Toast,表示走了这个方法

第四步

  就是MainActivity,这里我贴出代码

package com.haichenyi.myproject;

import android.os.Bundle;

import com.haichenyi.myproject.base.BaseMvpActivity;
import com.haichenyi.myproject.contract.MainContract;
import com.haichenyi.myproject.presenter.MainPresenter;

public class MainActivity extends BaseMvpActivity<MainPresenter> implements MainContract.IView {

  @Override
  protected int getLayoutId(Bundle savedInstanceState) {
    return R.layout.activity_main;
  }

  @Override
  protected void initData() {
    super.initData();
    initToolbar(true, false, true).setMyTitle("主页").setMoreTitle("更多");
    basePresenter.loadData();
  }

  @Override
  protected void initInject() {
    getActivityComponent().inject(this);
  }
}

  这里我需要说明的是继承BaseMvpActivity,泛型直接传MainPresenter,然后,实现MainContract.IView接口,直接用basePresenter调用方法,需要实现initInject方法,只要是是继承BaseMvpActivity的activity,都需要在ActivityComponent()里面注册一边。比方说,LoginActivity也是继承的BaseMvpActivity,辣么,在di层的component包下面的ActivityComponent接口里面定义一个方法

void inject(LoginActivity loginActivity);

在LoginActivity的initInject方法里面写同样的代码

getActivityComponent().inject(this);

就像这样写就可以了。

总结

  写到这里,mvp+dagger2基本上完成了,MVP的目的就是解藕,把业务逻辑,网络请求丢在P层,页面不发生变化,就只用改P层逻辑,从而达到了解藕的目的。dagger2简化了代码,并且,它有着全局单例模式,和局部单例模式,优化了我们的内存,减少了内存浪费。不用每次都去new一个P层对象出来。下一篇,我们就把网络请求加上

项目链接

    原文作者:海晨忆
    原文地址: https://www.jianshu.com/p/2fa1329bc27e
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞