Dagger2使用详解
2017-04-27 21:27
169 查看
Dagger2使用详解
什么是依赖注入?
依赖注入就是将调用者依赖的对象实例通过一定的方式从外部传入,解决了各个类之间的耦合问题。这个外部,正是dagger2容器。需要什么对象从容器中取就行了,调用和被调用方被隔离开,通过一个容器将他们联系起来,从而实现了解耦。
Dagger2是Google出的依赖注入框架。Dagger2的原理是在编译期生成相应的依赖注入代码。其他框架是在运行时期反射获取注解内容,影响运行效率。
引入Dagger2
在app的build.grade中引入android-apt,并添加dagger2依赖apply plugin: 'com.neenbedankt.android-apt' dependencies { apt "com.google.dagger:dagger-compiler:2.11-rc1" provided 'org.glassfish:javax.annotation:10.0-b28' compile "com.google.dagger:dagger:2.11-rc1" }
在project级别的build.grade中添加android-apt
buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:2.2.2' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' } }
Dagger2基本用法
@Inject通常在需要依赖的地方使用这个注解,换句话说,你用它告诉dagger2这个类或这个字断需要依赖注入,这样dagger2就会构造一个这个类的实例去满足他们的依赖
@Module
Module类里面的方法专门提供依赖,所以我们定义一个类,用@Module注解,这样dagger2在构造类实例的时候就知道去哪里找这些依赖。
@Provide
在Module中,我们定义的方法使用这个注解,告诉dagger2我们想要构造对象并提供这些依赖
@Component
Component是一个注入器,也可以说是连接Inject和Module的桥梁
下面看个例子,通过例子来看下dagger2的基本用法:
// MainActivity.java public class MainActivity extends AppCompatActivity { @Inject LoginManager loginManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); DaggerLoginModuleComponent.create().inject(this); loginManager.login(); } }
调用LoginManager的login接口,因此需要将LoginManager对象注入到MainActivity中,注入的操作由DaggerLoginModuleComponent调用inject方法完成的,LoginModuleComponent是怎么和LoginManager关联上的呢?
// LoginModuleComponent.java @Component(modules = {LoginModule.class}) public interface LoginModuleComponent { void inject(MainActivity activity); }
事实上,LoginModuleComponent只是LoginModule和MainActivity的连接器,可以想象成注射器,把LoginModule提供的对象注射到MainActivity中,完成依赖注入的过程。再看下LoginModule中提供了哪些对象?
// LoginModule.java @Module public class LoginModule { @Provides public LoginManager providerLoginManager() { return new LoginManager(); } } // LoginManager.java public class LoginManager { public void login() { Log.i("dagger2", "--- login ---"); } }
可以看到是通过Provides注解来提供LoginManager对象的,用起来还是很简单的,运行一下:
04-27 18:38:05.893 2343-2343/com.testdes.des I/dagger2: --- login ---
Dagger2模块化
LoginManager中执行login操作,需要OkHttpClient对象,我们从构造方法中传入,如下:// LoginManager.java public class LoginManager { OkHttpClient client; public LoginManager(OkHttpClient client) { this.client = client; } public void login() { Log.i("dagger2", "--- login:" + client); } } // LoginModule.java @Module public class LoginModule { @Provides public LoginManager providerLoginMgr(OkHttpClient client) { Log.i("dagger2", "--providerLoginMgr"); return new LoginManager(client); } @Provides public OkHttpClient okHttpClient() { return new OkHttpClient(); } }
考虑到OkHttpClient不仅仅在登录的时候使用,其它网络操作也需要这个对象,因此把OkHttpClient做成公共模块,通过HttpModule提供出来。
// HttpModule.java @Module public class HttpModule { @Provides public OkHttpClient providerOKHTTP() { return new OkHttpClient(); } } // LoginModule.java @Module(includes = {HttpModule.class}) public class LoginModule { @Provides public LoginManager providerLoginMgr(OkHttpClient client) { Log.i("dagger2", "--providerLoginMgr"); return new LoginManager(client); } }
在LoginModule中通过includes属性把HttpModule引入进来就可以了,实现了简单的HttpModule模块化,当然还有其他的方式,比如在LoginModuleComponent中引入HttpModule
@Component(modules = {LoginModule.class, HttpModule.class}) public interface LoginModuleComponent { void inject(MainActivity activity); }
或者创建HttpComponent,通过dependencies依赖,如下:
@Component(modules = {LoginModule.class}, dependencies = HttpComponent.class) public interface LoginModuleComponent { void inject(MainActivity activity); }
Dagger2单例
单例只需要使用@Singleton注解来声明,当HttpModule的providerOKHTTP使用了Singleton,LoginModuleComponent也需要使用Singleton来标注,如下:// HttpModule.java @Module public class HttpModule { @Provides public OkHttpClient providerOKHTTP() { return new OkHttpClient(); } } // LoginModuleComponent.java @Component(modules = {HttpModule.class}) @Singleton public interface LoginModuleComponent { void inject(MainActivity activity); } // MainActivity.java public class MainActivity extends AppCompatActivity { @Inject OkHttpClient okHttpClient; @Inject OkHttpClient okHttpClient2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); DaggerLoginModuleComponent.create().inject(this); Log.i("dagger2", ""+okHttpClient); Log.i("dagger2", ""+okHttpClient2); } }
运行一下,确实是单例
04-28 14:47:03.553 8497-8497/com.testdes.des I/dagger2: com.testdes.des.dagger2.OkHttpClient@3ef1ff 04-28 14:47:03.553 8497-8497/com.testdes.des I/dagger2: com.testdes.des.dagger2.OkHttpClient@3ef1ff
我们在增加一个页面SettingActivity,假设有个登出的功能,也需要用到OkHttpClient,代码不贴了,运行一下:
04-28 15:29:47.999 9781-9781/com.testdes.des I/dagger2: MainActivity:com.testdes.des.dagger2.OkHttpClient@3ef1ff 04-28 15:29:48.068 9781-9781/com.testdes.des I/dagger2: SettingActivity:com.testdes.des.dagger2.OkHttpClient@ba0d601
哇擦,又发现不单例了!!这是什么鬼?
这里解释下,dagger2的单例和传统java单例不一样,我们通常说的单例是在静态域里初始化的,只要程序不退出就一直保持单例,而dagger2单例是依附于component,即使声明了singleton,不同的component也不是单例,参考文章末尾的注意事项第7条。
所以我们如果要实现单例,需要怎么做呢?
思路是定义一个HttpComponent,作为其他component的dependencies component,具体如下:
// HttpComponent.java @Component(modules = {HttpModule.class}) @Singleton public interface HttpComponent { } // LoginModuleComponent.java @Component(dependencies = {HttpComponent.class}) @Singleton public interface LoginModuleComponent { void inject(MainActivity activity); }
运行一下,发现报错了
Error:(11, 1) error: This @Singleton component cannot depend on scoped components: @Singleton com.testdes.des.dagger2.HttpComponent
错误原因参考文章末尾注意事项第4条,Singleton是一个scope, LoginModuleComponent和HttpComponent的scope不能相同,那我们只好给LoginModuleComponent自定义一个scope了,怎么定义可以参考Singleton
// ActivityScope.java @Scope @Documented @Retention(RUNTIME) public @interface ActivityScope { } // LoginModuleComponent.java @Component(dependencies = {HttpComponent.class}) @ActivityScope public interface LoginModuleComponent { void inject(MainActivity activity); }
运行一下,终于还是报错了
Error:(13, 8) error: com.testdes.des.dagger2.OkHttpClient cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method. com.testdes.des.dagger2.OkHttpClient is injected at com.testdes.des.MainActivity.okHttpClient com.testdes.des.MainActivity is injected at com.testdes.des.dagger2.LoginModuleComponent.inject(activity)
LoginModuleComponent没有办法得到HttpComponent提供的OkHttpClient对象,这是需要做一个桥接,增加一个get方法(名字任意取),返回一个OkHttpClient对象,如下
@Component(modules = {HttpModule.class}) @Singleton public interface HttpComponent { OkHttpClient get(); }
BUILD SUCCESSFUL
在MainActivity中注入的方法修改下:
// MainActivity.java DaggerLoginModuleComponent.builder() .httpComponent(DaggerHttpComponent.create()).build().inject(this);
需要构建一个httpComponent对象,按照上面的写法,每次用到都要调用DaggerHttpComponent.create()显然不合理,因此我们把httpComponent构建操作放到Application初始化的时候执行一次,如下:
// TestApplication.java public class TestApplication extends Application{ HttpComponent httpComponent; @Override public void onCreate() { super.onCreate(); System.out.println("start TestApplication"); httpComponent = DaggerHttpComponent.create(); } public HttpComponent getHttpComponent() { return httpComponent; } } // MainActivity.java DaggerLoginModuleComponent.builder() .httpComponent(((TestApplication)getApplication()).getHttpComponent()).build().inject(this);
SettingActivity中的写法和MainActivity保持一致,然后运行一下:
04-28 16:25:50.715 11228-11228/com.testdes.des I/dagger2: MainActivity:com.testdes.des.dagger2.OkHttpClient@39f1d88 04-28 16:25:50.769 11228-11228/com.testdes.des I/dagger2: SettingActivity:com.testdes.des.dagger2.OkHttpClient@39f1d88
终于单例了,以上是dagger2的基本用法和单例的实现,谢谢~
注意事项
component的inject方法接收父类型参数,而传入的是子类型的对象则无法注入component关联的modules中不能有重复的provide
module中的provide方法使用了scope,则component需要使用同一个注解
component的dependencies与component自身不能使用同一个scope,即组件之间的scope不能相同
singleton的组件不能依赖其他scope组件,只能其他scope组件依赖singleton
没有scope的组件不能依赖有scope的组件
@singleton的生命周期依附于component,同一个module provide singleton,不同的component也不是单例
相关文章推荐
- Android 神兵利器Dagger2使用详解(一)基础使用
- Android Dagger2(一) Dagger使用详解
- 详解Kotlin 中使用和配置 Dagger2
- Dagger2 使用详解
- Android 神兵利器Dagger2使用详解(四)Scope注解的使用及源码分析
- Android 神兵利器Dagger2使用详解(三)MVP架构下的使用
- Android 神兵利器Dagger2使用详解(二)Module&Component源码分析
- 告别Dagger2模板代码:Dagger Android使用详解
- Android 依赖注入库——Dagger2使用详解
- Dagger2 使用详解
- Dagger2使用详解------比较清晰明了
- dagger2使用详解
- iOS:SDWebImage使用详解
- Linux下动态共享库加载及使用详解【转】
- 详解PHP fsockopen的使用方法(获取页面的头信息)
- 堆的详解和使用
- launchMode使用详解
- linux系统rootkit恶意软件安全检测工具rkhunter安装部署、使用详解
- Android中View(视图)绘制不同状态背景图片原理深入分析以及StateListDrawable使用详解
- MongoDB学习(三)MongoDB 3.2.8的使用详解