个人博客: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+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层对象出来。下一篇,我们就把网络请求加上