本文使用dagger2构建MVP框架,目的是加深dagger2的理解,一个小demo,记录分享之。 相关文章: Android Mvp实践 Android中利用泛型简化MVP
总体框架
### 工程目录结构 整个工程的目录结构如下: base文件夹存放一些公用的基类文件,di文件夹存放依赖注入相关的代码,mvp中按功能模块划分。本demo实现的功能为:通过点击界面上的按钮,获取手机系统时间并显示。
具体实现
### 在项目中引入dagger ```java 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中的方法。 ```java public abstract class BaseActivity<P extends BasePresenter> 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中的方法
java
public class BasePresenter
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的生成方法 ```java public class TempLatePresenter extends BasePresenter<TempLateContract.View> {
@Inject
public TempLatePresenter(TempLateContract.View rootView) {
super(rootView);
}
public void getTime() {
mRootView.setTime(System.currentTimeMillis() + "");
}
}
### 依赖注入
@Module中提供TempLateContract.View的构造方法
```java
@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
java
@ActivityScope
@Component(modules = TempLateModule.class, dependencies = AppComponent.class)
public interface TempLateComponent {
void inject(TempLateActivity activity);
}
### view层的具体实现
TempLateActivity中调用ComponentInject,实现依赖注入
```java
public class TempLateActivity extends BaseActivity
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 ```java @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的方法 ```java @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。 ```java @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修饰一下: ```java 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 } ```