Dagger2是一款非常优秀的依赖注入框架,依然简单去讲,首先必须明确一个理念:依赖注入是实现控制反转的方式之一,所以先普及一下依赖注入和控制反转的两个基本概念:
控制反转:简单的说就是如果你需要创建(new),那么别自己手敲,把它交给三方框架去做。控制反转是面向对象编程的一种设计模式,目的就是降低代码的耦合性。
依赖注入:拿Android打比方,一个Activity中可能需要很多的类实例,中规中矩的写法就是需要什么就new什么,咣咣一顿new,用依赖注入的写法的话,只需要写明特定的框架标识,让依赖注入的框架往Activity中自动增加需要new的东西就行了,不用自己去写实例化的对象了。
Dagger2多用于Android的MVP模式,最大的好处是降低了代码的耦合性,避免了因为A这个类的代码改了,所以B.class也要更改的关联改动的现象,按照Dagger的语法标识好,写好相应的interface接口,Dagger就会自动生成目标代码用来提供依赖注入的操作。Dagger2的集成使用也要先说几个涉及的基本概念词:依赖 ,需求者, 纽带。先说理论性的描述,在列举完理论之后会用Demo的代码去具体分析。
需求者:引入依赖的一方就是需求者
依赖:用伪代码去理解,两个类老虎类和牙齿类,老虎生存捕食,牙齿是被老虎依赖的关系
class 牙齿{
public 牙齿() {
}
}
class 老虎 {
牙齿 b;
public 老虎() {
b = new 牙齿();
}
}
如果用Dagger的格式依赖注入的话,那么上述代码就会变成下图。老虎的@Inject声明在属性上,说明它是一个需求者,牙齿的@Inject在构造函数上,说明牙齿是一个依赖,这种是最简单的依赖提供形式。
class 牙齿{
@Inject
public 牙齿() {
}
}
class 老虎 {
@Inject
牙齿 b;
}
依赖一般有2种方式,一是通过@Inject构造函数的方式提供,二是通过Module的方式提供。但是光有依赖和需求者是不够的,必须有一个纽带来维系才能让Dagger2正常的工作。
纽带:@Component来标识,被标注了Component的接口在编译时会产生相应的类的实例来作为提供依赖方和需求者之间的纽带。下面是纽带的三种常见写法:
@Component()
public interface Platform {
ZhaiNan waimai(); //带返回值就算是一种依赖的提供
}
@Component(modules = ShangjiaAModule.class) //@Component()里的.class就是提供的涉及三方库的依赖
public interface WaimaiPingTai {
ZhaiNan waimai();
}
@Component(modules = ShangjiaAModule.class)
public interface WaimaiPingTai {
void zhuru(MainActivity mainActivity); //在方法中传入类型参数。目的是针对这个参数对象进行依赖注入
}
值得注意的是,dagger2有两种@inject提供依赖,和provide提供依赖。Dagger2 依赖查找的顺序是先查找 Module 内所有的 @Provides 提供的依赖,如果查找不到再去查找 @Inject 提供的依赖。下面还是用Demo的代码去一点一点的分析理解Dagger2如何在MVP项目中实战,先看效果图:
效果图
Demo实现的效果很简单,点击界面上的搜索按钮,会发送http协议获取某个城市的经纬度,当获取到http请求回执后,反序列化Json,然后重新绘制界面,显示经纬度。从MVP的模式去讲,这个包含搜索Button的,点击搜索后弹出的转圈等待界面就是View层,当响应点击事件之后,View层就会通知Presenter层,让Presenter去发送获取经纬度的http协议,并且在Presenter中监听http协议的回执,若协议收发成功,那么presenter就会通知View层去重新绘制UI,Dagger2用来依赖注解Presenter,发送协议的等待转圈dialog和Retrofit2.0。
下面贴出具体代码进行理解 ,先是依赖注入Presenter部分 :
/**
* Created by xjc on 2018/11/26.
*/
public abstract class IBaseActivity extends BaseActivity implements Stateful {
@Inject
protected T mPresenter;
private Unbinder bind;
QMUITipDialog tipDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bind = ButterKnife.bind(this);
initView();
initInject();
if (mPresenter != null)
mPresenter.attachView(this);
loadData();
}
public void createLoading(){
tipDialog = new QMUITipDialog.Builder(this)
.setIconType(QMUITipDialog.Builder.ICON_TYPE_LOADING)
.setTipWord("正在加载")
.create();
tipDialog.show();
}
public void dismiss(){
if (tipDialog != null)
tipDialog.dismiss();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (bind != null) {
bind.unbind();
}
if (mPresenter!=null){
mPresenter.detachView();
}
}
protected abstract void loadData();
protected abstract void initView();
/**
* dagger2注入
*/
protected abstract void initInject();
每一个VIew界面都需要Presenter作为中介,如此以来项目中将Presenter提到界面的基类IBaseActivity中通过依赖注入的方式创建,@Inject 就是Dagger2的标识符,加在了属性之上说明这个IBaseActivty是需求者的身份,而Presenter是作为一个依赖被注入,接下来看Presenter 的实现类:
public class MainPresenterImpl extends BasePresenter implements MainPresenter.Model{
private ApiHttpService apiHttpService;
@Inject
public MainPresenterImpl(ApiHttpService apiHttpService) {
this.apiHttpService = apiHttpService;
}
@Override
public void getLonLat() {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("a","大连");
} catch (JSONException e) {
e.printStackTrace();
}
invoke(apiHttpService.fetchLocation(jsonObject.toString()),new Callback(){
@Override
public void onResponse(LocationResponseBean bean){
mView.refreshViewMistakeIntruductionList(bean);
}
});
}
}
注意在构造函数上也有 @Inject的标识,这说明了告诉了Dagger2框架Presenter的身份是一个依赖。当build项目后可以在编译生成的文件中查找到Dagger2生成的文件,其中以_MembersInjector结尾的就是上面所说的注入器,然后就能在页面代码进行依赖注入的操作:
下面是为了http通信的Retrofit依赖注入的部分:
/**
* Created by quantan.liu on 2017/4/8.
*/
@Singleton
@Component(modules = { ApiHttpModule.class})
public interface MainComponent {
void injectMain(MainActivity activity);
}
这是纽带的代码,从而可知依赖是ApiHttpModule.class, 根据上面所列举的纽带第三种写法可知是往MainActivity注入,需求者是MainActivity,接下来看依赖的代码:
/**
* Created by xjc on 2018/11/26.
*/
@Module
public class ApiHttpModule extends BaseHttpModule {
@Singleton
@Provides
Retrofit provideApiHttpRetrofit(Retrofit.Builder builder, OkHttpClient client) {
return createRetrofit(builder, client, ApiHttpService.API_URL);
}
@Singleton
@Provides
ApiHttpService provideApiHttpService( Retrofit retrofit) {
return retrofit.create(ApiHttpService.class);
}
}
/**
* Created by xjc on 2018/11/26.
*/
@Module
public class BaseHttpModule {
/**
* 提供http的帮助依赖 以下部分现在都放在子类。
* @return
*/
@Singleton
@Provides
Retrofit.Builder provideRetrofitBuilder() {
return new Retrofit.Builder();
}
@Singleton
@Provides
OkHttpClient.Builder provideOkHttpBuilder() {
return new OkHttpClient.Builder();
}
@Singleton
@Provides
OkHttpClient provideClient(OkHttpClient.Builder builder) {
//设置超时
builder.connectTimeout(10, TimeUnit.SECONDS);
builder.readTimeout(20, TimeUnit.SECONDS);
builder.writeTimeout(20, TimeUnit.SECONDS);
//错误重连
builder.retryOnConnectionFailure(true);
return builder.build();
}
protected Retrofit createRetrofit(Retrofit.Builder builder, OkHttpClient client, String url) {
return builder
.baseUrl(url)
.client(client)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(AESGsonConverterFactory.create())
.build();
}
}
最后在主界面中通过Dagger2自动生成的代码文件进行依赖注入,就完成了依赖注入的所有操作:
DaggerMainComponent.builder().apiHttpModule(new ApiHttpModule()).build().injectMain(this);
Demo已打包上传:https://download.csdn.net/download/crystal_xing/10811027