简介
本文使用dagger2构建MVP框架,目的是加深dagger2的理解,一个小demo,记录分享之。
相关文章:
Android Mvp实践
Android中利用泛型简化MVP
CSDN同步发布
总体框架
工程目录结构
整个工程的目录结构如下:
base文件夹存放一些公用的基类文件,di文件夹存放依赖注入相关的代码,mvp中按功能模块划分。本demo实现的功能为:通过点击界面上的按钮,获取手机系统时间并显示。
具体实现
在项目中引入dagger
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}
apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
dependencies {
//other dependencies
//Dagger2
compile 'com.google.dagger:dagger:2.0.2'
compile 'javax.annotation:jsr250-api:1.0'
apt 'com.google.dagger:dagger-compiler:2.0.2'
}
BaseActivity
BaseActivity中传入Presenter,利用@Inject注解Presenter,Dagger2会自动去找Presenter的生成方法,并创建presenter对象,则activity中持有presenter对象,可调用presenter中的方法。
public abstract class BaseActivity extends Activity {
protected MyApplication myApplication;
@Inject
protected P mPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(initView());
myApplication = (MyApplication) getApplication();
ComponentInject(myApplication.getAppComponent());//依赖注入
initData();
}
/**
* 依赖注入的入口
*/
protected abstract void ComponentInject(AppComponent appComponent);
protected abstract View initView();
protected abstract void initData();
}
BasePresenter
BasePresenter中传入BaseView接口,持有view接口,可调用view中的方法
public class BasePresenter implements presenter{
protected V mRootView;
public BasePresenter(V rootView) {
this.mRootView = rootView;
onStart();
}
@Override
public void onStart() {
}
@Override
public void onDestroy() {
}
}
presenter层的具体实现
TempLatePresenter的构造方法使用了@Inject注解,在上面的BaseActivity中自动构造TempLatePresenter对象时就是从这里产生的TempLatePresenter对象,同时该构造方法中还传入了TempLateContract.View参数,因此dagger2会继续寻找TempLateContract.View的生成方法
public class TempLatePresenter extends BasePresenter {
@Inject
public TempLatePresenter(TempLateContract.View rootView) {
super(rootView);
}
public void getTime() {
mRootView.setTime(System.currentTimeMillis() + "");
}
}
依赖注入
@Module中提供TempLateContract.View的构造方法
@Module
public class TempLateModule {
private TempLateContract.View view;
public TempLateModule(TempLateContract.View view) {
this.view = view;
}
@ActivityScope
@Provides
TempLateContract.View provideTempLateView() {
return this.view;
}
}
TempLateComponent管理该module
@ActivityScope
@Component(modules = TempLateModule.class, dependencies = AppComponent.class)
public interface TempLateComponent {
void inject(TempLateActivity activity);
}
view层的具体实现
TempLateActivity中调用ComponentInject,实现依赖注入
public class TempLateActivity extends BaseActivity implements TempLateContract.View{
Button btnGetTime;
TextView tvTime;
@Override
protected void ComponentInject(AppComponent appComponent) {
DaggerTempLateComponent
.builder()
.appComponent(appComponent)
.tempLateModule(new TempLateModule(this)) //请将TempLateModule()第一个首字母改为小写
.build()
.inject(this);
}
@Override
protected View initView() {
return LayoutInflater.from(this).inflate(R.layout.activity_template, null, false);
}
@Override
protected void initData() {
btnGetTime = (Button) findViewById(R.id.btn_get_time);
tvTime = (TextView) findViewById(R.id.tv_time);
btnGetTime.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mPresenter.getTime();
}
});
}
@Override
public void setTime(String time) {
tvTime.setText(time);
}
}
整体流程如下:
- TempLateActivity继承BaseActivity并传入TempLatePresenter,view中持有TempLatePresenter对象
- dagger2根据@inject注解知道要构造TempLatePresenter对象
- 找到TempLatePresenter的构造方法,该方法中持有view的引用,发现还需要TempLateContract.View参数
- 在TempLateModule中找到TempLateContract.View的构造方法
- 依次完成TempLateContract.View和TempLatePresenter的构造
Dagger2简单理解
Module中提供Dependency
@Module
public class AppModule {
public AppModule(Context context) {
this.mContext = context;
}
@Provides
public Context provideContext() {
return mContext;
}
@Provides
public OkHttpClient provideOkHttpClient() {
OkHttpClient okhttpClient = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.build();
return okhttpClient;
}
@Provides
public Retrofit provideRetrofit(OkHttpClient okhttpClient) {
Retrofit retrofit = new Retrofit.Builder()
.client(okhttpClient)
.baseUrl("https://api.github.com")
.build();
return retrofit;
}
}
这种用来生产Dependency的、用 @Provides修饰过的方法叫Provider方法。如果最后找到的 provideOkHttpClient()方法也需要其他参数,那么管理员还会继续递归的找下去,直到所有的Dependency都被满足了,再一个一个创建Dependency
工厂管理员:Component
方法一:在Component里面定义一个返回Dependency的方法
@Component(modules = {AppModule.class})
public interface AppComponent {
LoginPresenter loginPresenter();
}
public class LoginActivity extends AppCompatActivity {
private LoginPresenter mLoginPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AppComponent appComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build(); //<=
mLoginPresenter = appComponent.loginPresenter(); //<=
}
}
方法二:Field Injection
DaggerAppComponent实现这个方法的方式是,去LoginActivity里面所有被 @Inject修饰的field,然后调用 AppModule相应的Provider方法,赋值给这个field。这里需要注意的是,@Inject field不能使private,不然dagger2找不到这个field。
@Component(modules = {AppModule.class})
public interface AppComponent {
void inject(LoginActivity loginActivity); //<=
}
public class LoginActivity extends AppCompatActivity {
@Inject
LoginPresenter mLoginPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AppComponent appComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build(); //<=
appComponent.inject(this); //<=
//从此之后,mLoginPresenter就被实例化了
//mLoginPresenter.isLogin()
}
}
其实AppModule里面的很多Provider方法是不需要定义的。比如说在这种情况下,LoginPresenter的Provider方法 provideLoginPresenter(UserManager userManager, PasswordValidator validator) 就不需要定义,你只需要在定义LoginPresenter的时候,给它的Constructor加上 @Inject修饰一下:
public class LoginPresenter {
private final UserManager mUserManager;
private final PasswordValidator mPasswordValidator;
@Inject
public LoginPresenter(UserManager userManager, PasswordValidator passwordValidator) {
this.mUserManager = userManager;
this.mPasswordValidator = passwordValidator;
}
//other methods
}
源码已上传github
参考文章
使用dagger2来做依赖注入,以及在单元测试中的应用