前言
Dagger2依赖注入框架,为了降低程序间的耦合度,防止产生牵一发而动全身的问题。
除此之外,它同样还有很多优点:
增加开发效率、省去重复的简单体力劳动
首先new一个实例的过程是一个重复的简单体力劳动,dagger2完全可以把new一个实例的工作做了,因此我们把主要精力集中在关键业务上、同时也能增加开发效率上。省去写单例的方法,并且也不需要担心自己写的单例方法是否线程安全,自己写的单例是懒汉模式还是饿汉模式。因为dagger2都可以把这些工作做了。
更好的管理类实例
每个app中的ApplicationComponent管理整个app的全局类实例,所有的全局类实例都统一交给ApplicationComponent管理,并且它们的生命周期与app的生命周期一样。每个页面对应自己的Component,页面Component管理着自己页面所依赖的所有类实例。因为Component,Module,整个app的类实例结构变的很清晰。
解耦
假如不用dagger2的话,一个类的new代码是非常可能充斥在app的多个类中的,假如该类的构造函数发生变化,那这些涉及到的类都得进行修改。设计模式中提倡把容易变化的部分封装起来。我们用了dagger2后。假如是通过用Inject注解标注的构造函数创建类实例,则即使构造函数变的天花乱坠,我们基本上都不需要修改任何代码。假如是通过工厂模式Module创建类实例,Module其实就是把new类实例的代码封装起来,这样即使类的构造函数发生变化,只需要修改Module即可。
有个网友问过一个这样的问题,Module的构造函数也会发生变化,发生变化后,相应的new Module的类也发生变化,这就没有达到解耦的效果。首先解耦不是说让类之间或模块之间真的一点关系都没有了,解耦达到的目的是让一个类或一个模块对与自己有关联的类或模块的影响降到最低,不是说这种影响就完全没有了,这是不可能的。
解耦还有个好处,就是方便测试,若需要替换为网络测试类,只需要修改相应的Module即可。
1、首先添加依赖:
Project gradle:
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
Module gradle:
apply plugin: 'com.neenbedankt.android-apt'
....
provided 'org.glassfish:javax.annotation:10.0-b28'
compile 'com.google.dagger:dagger:2.5'
compile 'com.google.dagger:dagger-compiler:2.5'
2、简单使用:
public class UserStore {
public void register() {
}
}
public class ApiService {
public void register() {
}
}
//是Inject和Provides之间的桥梁
//这句话关联到modules
@Component(modules = {UserModule.class})
public interface UserComponet {
//这句话关联到MainActivity
void inject(MainActivity activity);
}
@Module
public class UserModule {
//提供依赖
@Provides
public ApiService provideApiService() {
return new ApiService();
}
}
public class MainActivity extends AppCompatActivity {
//告诉Dagger,这个类需要注入对象
@Inject
ApiService mApiService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//需要先Rebuild Project
DaggerUserComponet.create().inject(this);
mApiService.register();
}
}
UserStore用来将用户数据保存到本地,ApiService获取网络数据,UserManager负责管理这两个对象,@Inject注解是用来告诉Dagger2这个类是需要依赖注入,@Component(modules = {UserModule.class})关联到UserModule,UserModule中的provideApiService()方法用了提供实例对象,void inject(MainActivity activity)是用来关联到activity,这样@Inject就与@Module通过@Component关联。
常用注解:
3、进一步使用:
@Module
public class UserModule {
private Context mContext;
public UserModule(Context context) {
this.mContext = context;
}
@Provides
public UserStore providesUserStore() {
return new UserStore(this.mContext);
}
@Provides
public UserManager providesUserManager(ApiService apiService, UserStore userStore) {
return new UserManager(apiService, userStore);
}
}
public class UserStore {
public UserStore(Context context) {
Log.e("userstore","constructorUsertore");
}
public void register() {
}
}
//是Inject和Provides之间的桥梁
//这句话关联到modules
@Component(modules = {UserModule.class})
public interface UserComponet {
//这句话关联到MainActivity
void inject(MainActivity activity);
}
public class ApiService {
//当在UserModule中没有提供 返回ApiService实例的方法,就会去找这个类中的@Inject标注的构造方法
@Inject
public ApiService(){
Log.e("ApiService","constructorApiService");
}
public void register() {
}
}
public class UserManager {
private ApiService mApiService;
private UserStore mUserStore;
public UserManager(ApiService mApiService, UserStore mUserStore) {
this.mApiService = mApiService;
this.mUserStore = mUserStore;
}
public void register() {
mApiService.register();
}
}
public class MainActivity extends AppCompatActivity {
@Inject
UserManager userManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerUserComponet.builder().userModule(new UserModule(this)).build().inject(this);
userManager.register();
}
}
4、模块化实现
我们现在开发中用的最多的就是Okhttp或者是Retrofit,但是每次请求都要去实例化一个OkhttpClient或者Retrofit对象显然是没有必要的,这时就要统一做一个模块专门产生该对象。下面以Okhttp作为讲解的例子:
首先需要去单独定义这个Http模块:
@Module
public class HttpModule {
@Provides
public OkHttpClient mOkhttpClient() {
return new OkHttpClient().newBuilder().build();
}
}
public class ApiService {
OkHttpClient mOkHttpClient;
public static final MediaType JSON = MediaType.parse("application/json;charset=utf-8");
public ApiService(OkHttpClient okHttpClient) {
Log.e("ApiService", "constructorApiService");
this.mOkHttpClient = okHttpClient;
}
public void register() {
Log.e("ApiService", "ApiService--register");
RequestBody body = RequestBody.create(JSON, "");
Request request = new Request.Builder().url("").post(body).build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
}
@Module(includes = {HttpModule.class})
public class UserModule {
private Context mContext;
public UserModule(Context context) {
this.mContext = context;
}
//提供依赖
@Provides
public ApiService provideApiService(OkHttpClient client) {
return new ApiService(client);
}
@Provides
public UserStore providesUserStore() {
return new UserStore(this.mContext);
}
@Provides
public UserManager providesUserManager(ApiService apiService, UserStore userStore) {
return new UserManager(apiService, userStore);
}
}
}
为了得到ApiService的实例,就需要得到okhttpClient实例,这里将几种方式抽取出来:
方式一:
上面的@Module(includes = {HttpModule.class})属于一种方式,将HttpMoule作为一个模块关联进来。
方式二:新建一个HttpComponet,UserComponet包含HttpComponet
@Component(modules = HttpModule.class)
public class HttpComponet {
}
//是Inject和Provides之间的桥梁
//这句话关联到modules
@Component(modules = {UserModule.class}, dependencies = HttpComponet.class)
public interface UserComponet {
//这句话关联到MainActivity
void inject(MainActivity activity);
}
方式三:在UserComponet直接写上关联进来的Module
@Component(modules = {UserModule.class,HttpModule.class})
public interface UserComponet {
//这句话关联到MainActivity
void inject(MainActivity activity);
}
以上的三种方式是实现模块化的三种方式,将网络请求模块单独抽取出来。
5、创建和区分不同实例
假入一个Activity中有两个相同的ApiService实例,一个用于dev下,一个是release下,该如何区分:
方式一:@Named
public class MainActivity extends AppCompatActivity {
//告诉Dagger,这个类需要注入对象
@Named("dev")
@Inject
ApiService mApiService;
@Named("release")
@Inject
ApiService mApiService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerUserComponet.builder().userModule(new UserModule(this)).httpModule(new HttpModule())
.build().inject(this);
}
}
public class UserModule {
private Context mContext;
public UserModule(Context context) {
this.mContext = context;
}
//提供依赖
@Named("release")
@Provides
public ApiService provideApiServiceForRelease(OkHttpClient client) {
return new ApiService(client);
}
@Named("dev")
@Provides
public ApiService provideApiServiceForDev(OkHttpClient client) {
return new ApiService(client);
}
}
方式二:
创建两个自定义注解:
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Release {
}
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Test {
}
public class MainActivity extends AppCompatActivity {
//告诉Dagger,这个类需要注入对象
@Test
@Inject
ApiService mApiService;
@Release
@Inject
ApiService mApiService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerUserComponet.builder().userModule(new UserModule(this)).httpModule(new HttpModule())
.build().inject(this);
}
}
public class UserModule {
private Context mContext;
public UserModule(Context context) {
this.mContext = context;
}
//提供依赖
@Release
@Provides
public ApiService provideApiServiceForRelease(OkHttpClient client) {
return new ApiService(client);
}
@Test
@Provides
public ApiService provideApiServiceForDev(OkHttpClient client) {
return new ApiService(client);
}
}
6、Singleton
当时使用Singleton的时候,需要在Module和Compont上同时加上@Singleton注解:
@Singleton
@Component(modules = {UserModule.class})
public interface UserComponet {
//这句话关联到MainActivity
void inject(MainActivity activity);
}
@Provides
@Singleton
OkHttpClient providesOkhttp() {
return new OkHttpClient().newBuilder().build();
}
7、自定义Scope
同一个Componet关联的Module的Scope不能与依赖的Componet的Scope相同,举例如下:
@Module
public class AppModule {
@Singleton
@Provides
OkHttpClient providesOkhttp() {
return new OkHttpClient().newBuilder().build();
}
}
@Singleton
@Component(modules = AppModule.class)
public interface AppCompont {
OkHttpClient okhttpClient();
}
@ActivityScope
@Component(modules = {UserModule.class},dependencies = AppCompont.class)
public interface UserComponet {
//这句话关联到MainActivity
void inject(MainActivity activity);
}
@Scope
@Documented
@Retention(RUNTIME)
public @interface ActivityScope {
}
上面的代码中自定义了一个Scope,是因为在Dagger中自身的Componet的Scope,不能与依赖的Componet的Scope一样,所以必须重新自定义一个Scope。
8、SubComponet和Lazyer与Provider
注意点:SubComponet同时具备两种不同的生命周期的scope,SubComponent具备了父Component拥有的Scope,也具备了自己的scope;SubCompnent的Scope范围小于Component。
@ActivityScope
@Subcomponent(modules = UtilModule.class)
public interface CComponet {
void inject(MainActivity activity);
}
@Singleton
@Component(modules = AppModule.class)
public interface FComponet {
CComponet getChildComponet();
}
@Module
public class UtilModule {
@Provides
@ActivityScope
public Gson providesGson(OkHttpClient okHttpClient){
return new Gson();
}
}
@Module
public class AppModule {
@Singleton
@Provides
OkHttpClient providesOkhttp() {
return new OkHttpClient().newBuilder().build();
}
}
Lazyer与Provider:
public class Container{
@Inject
Lazy<User> lazyUser;//注入Lazy元素
@Inject
Provider<User> providerUser;//注入Provider元素
public void init(){
DaggerFComponet.create().getChildComponet().inject(MainActivity.this);
User user1 = lazyUser.get();
//在这时创建user,以后每次调用get会得到同一个User对象
User user2 = providerUser.get();
//在这时创建use2,以后每次调用get会再强制调用Module的Provides方法一次,根据Provides方法具体实现的不同
//可能返回跟user2是同一个对象,也可能不是。
}
}
9、坑点(注意点):
上面就是我学习Dagger2的一些总结,其中可能会有些问题,欢迎大家指出,共同进步。