从零开始搭建一个主流项目框架(二)—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,项目结构图如下:

项目结构图.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层对象出来。下一篇,我们就把网络请求加上

项目链接

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容