Dagger2的简单使用
一、简单介绍
Dagger是一个依赖注入框架,所谓依赖注入其实是一种编程模式,目的是为了降低程序耦合。
1、基本概念
Inject
:用于在需要注入以来的地发那个进行朱姐
Module
:用于提供依赖,告诉Dagger从哪里去寻找依赖,一个App通常是一个或多个Module组成
Provide
:用这个方法表示注解
Component
:注入器,是Inject
和Module
的桥梁,用于连接这2个部分
二、基本使用
添加依赖
implementation 'com.google.dagger:dagger:2.19'
annotationProcessor 'com.google.dagger:dagger-compiler:2.19'
1、基本使用(不使用Module)
(1)将我们需要注入的对象使用@Inject
标注,告诉dagger2我们需要实例化这个类
public class Student {
private static final String TAG = "Student";
@Inject
public Student() {
}
public void say() {
Log.i(TAG, "say: 我们是学生");
}
}
(2)创建一个接口,并使用@Component
标注,然后写inject方法,这个方法表示,我们需要将依赖注入的位置
@Component
public interface PersonComponent {
void inject(NoModuleActivity noModuleActivity);
}
(3)编译程序(Ctrl+F9)后,我们可以在我们需要注入的类中,先通过@Inject
标注我们需要注入的类,然后使用系统生成的Component方法,系统会在我们的Component方法钱加上Dagger
,因为我们需要注入类的构造方法没有参数,因此我们使用create()方法,然后注入我们的变量,这样我们就可以使用这个对象了
public class NoModuleActivity extends AppCompatActivity {
@Inject
Student mStudent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_no_module);
DaggerPersonComponent.create().inject(this);
mStudent.say();
}
}
(4)打印的日志如下,这就表示我们的对象注入成功了
10-31 21:53:28.753 1140-1140/com.example.active.loser.dagger I/Student: say: 我们是学生
注:我们可以发现,我们不使用module也是很简单,且可以获取对象,但是我们若是使用第三方的一些库对象就必须使用module了,因为我们无法对他们的构造函数添加注解
2、module使用(无参)
假设我们需要提供Retrofit
(1)添加Retrofit
的依赖
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
(2)创建module,这个类的写法通常以module
结尾,并将这个类用@Module
表示,然后创建一个类,并写一个方法,返回我们的对象,通常用 provide开头,并使用@Provides
表示
@Module
public class RetrofitModule {
@Provides
public Retrofit provideRetrofit(){
return new Retrofit.Builder()
.baseUrl("https://www.hao123.com/")
.build();
}
}
(3)创建一个接口,并使用@Component
标注,并在括号里引入我们的Module
,然后写inject方法,这个方法表示,我们需要将依赖注入的位置
@Component(modules = {RetrofitModule.class})
public interface RetrofitComponent {
void inject(Module1Activity module1Activity);
}
(4)使用
public class Module1Activity extends AppCompatActivity {
private static final String TAG = "Module1Activity";
@Inject
Retrofit mRetrofit;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_module1);
DaggerRetrofitComponent.create().inject(this);
Log.i(TAG, "onCreate: " + mRetrofit.hashCode());
}
}
输出信息:
10-31 22:13:18.233 1495-1495/com.example.active.loser.dagger I/Module1Activity: onCreate: 1249382912
2、module使用(有参)
Module
有参数的使用和没有参数的使用方式基本相同,我们只在绑定的视图中绑定。
(1)我们还是用上面的例子,但是URL需要动态指定:
@Module
public class RetrofitModule {
String url;
public RetrofitModule(String url) {
this.url=url;
}
@Provides
public Retrofit provideRetrofit(){
return new Retrofit.Builder()
.baseUrl(url)
.build();
}
}
(2)使用的时候,我们通过builder()
模式, 然后传参。
public class Module1Activity extends AppCompatActivity {
private static final String TAG = "Module1Activity";
@Inject
Retrofit mRetrofit;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_module1);
DaggerRetrofitComponent.builder()
.retrofitModule(new RetrofitModule("https://www.hao123.com/"))
.build()
.inject(this);
Log.i(TAG, "onCreate: " + mRetrofit.hashCode());
}
}
(3)输出:
10-31 22:25:40.866 1178-1178/? I/Module1Activity: onCreate: 1249612184
扩展:我们可能想到,假如我们的构造函数需要传入对象,那这个对象有2中方式获得,第一种写一个provide方法,第二种将我们需要传入的对象的构造方法用@Inject
标注,另外,若构对象的造函数需要参数,一方面可以使用Module传入,另一个方面可以使用provide提供这个参数对象。
三、扩展使用
1、 include
》》Module依赖Module《《
include:可以简单的理解为Module
和Module
之间的监交互,使用的原因是因为若我们在RetrofitModule
中和ModuleA
中均需要使用Retrofit,我们只需要在RetrofitModule
中提供Retrofit
,在ModuleA
中通过include
引用RetrofitModule
就可以使用了。
(1)假设我们需要在ApiServer
使用Retrofit
,我们通过构造参数传入
public class ApiServer {
private Retrofit mRetrofit;
public ApiServer(Retrofit retrofit) {
mRetrofit = retrofit;
}
}
(2)创建ApiServerModule
,我们提供provideApiServer
,然后用过includes
引入RetrofitModule.class
,这样RetrofitModule
就可以使用RetrofitModule
中的Retrofit
了
@Module(includes = {RetrofitModule.class})
public class ApiServerModule {
@Provides
public ApiServer provideApiServer(Retrofit retrofit) {
return new ApiServer(retrofit);
}
}
(3)创建ApiServerComponent
@Component(modules = {ApiServerModule.class})
public interface ApiServerComponent {
void inject(IncludeActivity includeActivity);
}
(4)使用
public class IncludeActivity extends AppCompatActivity {
private static final String TAG = "IncludeActivity";
@Inject
ApiServer mApiServer;
@Inject
Retrofit mRetrofit;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_include);
DaggerApiServerComponent.builder()
.apiServerModule(new ApiServerModule())
.retrofitModule(new RetrofitModule("https://www.hao123.com/"))
.build()
.inject(this);
Log.i(TAG, "ApiServer: " + mApiServer.hashCode()+"Retrofit: " + mRetrofit.hashCode());
}
}
(5)通过打印,我们可以看出已经使用Retrofit
和ApiServer
了。
10-31 22:49:07.806 1363-1363/com.example.active.loser.dagger I/IncludeActivity: ApiServer: 1249565216Retrofit: 1249369216
2、dependence & subComponent
》》Component依赖Component《《
当我们其中一个Component跟另外一个Component所提供的依赖有重复的时候,我们没有必要完全再写一遍,一个Component是可以依赖另外一个依赖的,理解起来就像extends,我们㓟
2.1、dependence:
- 父Component中要显式的写出需要暴露可提供给子Component的依赖;
- 子Component在注解中使用dependencies=来连接父Component;
使用
(1)我们还是使用之前的RetrofitComponent,我们用Retrofit getRetrofit();
暴露可提供给子Component的依赖;
@Component(modules = {RetrofitModule.class})
public interface RetrofitComponent {
Retrofit getRetrofit();
void inject(Module1Activity module1Activity);
void inject(DependenceActivity dependenceActivity);
}
(2)子Component在注解中使用dependencies=来连接父Component;
@Component(dependencies = {RetrofitComponent.class})
public interface DependenceComponent {
void inject(DependenceFragment dependenceFragment);
}
(3)我们通常有很多方法既需要在Activity中使用,也需要在Fragment使用,下面通过简单的例子
public class DependenceActivity extends AppCompatActivity {
private RetrofitComponent mRetrofitComponent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dependence);
mRetrofitComponent = DaggerRetrofitComponent.builder()
.retrofitModule(new RetrofitModule("https://www.hao123.com/"))
.build();
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment, new DependenceFragment())
.commit();
}
//提供RetrofitComponent
public RetrofitComponent getRetrofitComponent() {
return mRetrofitComponent;
}
}
public class DependenceFragment extends Fragment {
private static final String TAG = "DependenceFragment";
@Inject
Retrofit mRetrofit;
//........
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
RetrofitComponent retrofitComponent = ((DependenceActivity) getActivity())
.getRetrofitComponent();
if (retrofitComponent!=null) {
DaggerDependenceComponent.builder()
.retrofitComponent(retrofitComponent)
.build()
.inject(this);
Log.i(TAG, "onViewCreated: "+mRetrofit.hashCode());
}
}
}
输出
11-03 18:45:16.200 1446-1446/com.example.active.loser.dagger I/DependenceFragment: onViewCreated: 1249920380
2.2、subComponent:
Subcomponent
的使用方法与dependence
基本相同
-
先定义子Component,使用@Subcomponent标注(不可同时再使用@Component);
@Subcomponent public interface SubComponent { void inject(DependenceFragment dependenceFragment); }
-
父Component中定义获得子Component的方法;
@Component(modules = {RetrofitModule.class}) public interface RetrofitComponent { void inject(DependenceActivity dependenceActivity); SubComponent getSubComponent(); }
3、@Singleton & @Scope
》》Component和Module《《
@Scope
其实是一个 元注解,用于描述注解的注解,其中@Singleton
是Scope默认提供的,表示单例,说到单例我们用一段简单的例子说明@Singleton
& @Scope
。
3.1、全局单例:
整个应用内只会存在一个对象,这也是我们在开发中常用的一种设计模式,一般写法都是这样:设计模式之单例,但是用了Dagger
之后,我们只需要在需要创建单例的Module
和Component
添加@Singleton
注解。
@Module
public class AppModule {
//.......
@Provides
@Singleton//全局单例
SharedPreferences provideSharedPreferences() {
return application.getSharedPreferences("spfile", Context.MODE_PRIVATE);
}
@Provides
MyApplication provideApplication() {
return application;
}
}
@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
SharedPreferences sharedPreferences();
MyApplication myApplication();
}
3.2、局部单例:
局部单例简单的就是说我们的对象在某个Activity和Fragment中是单例,但在不同的View中则没有关系。
(1)自定义@Scope
@Scope //声明这是一个自定义@Scope注解
@Retention(RUNTIME)
public @interface ActivityScope {
}
(2) 在Module
中添加我们定义的注解
@Module
public class ActivityModule {
private TestActivity activity;
public ActivityModule(TestActivity activity) {
this.activity = activity;
}
@Provides
@ActivityScope//添加我们自定义的注解
Student provideStudent() {
return new Student();
}
}
(3) 在Component
中添加我们定义的注解
@ActivityScope//添加我们自定义的注解
@Component(modules = TestModule.class, dependencies = AppComponent.class)
public interface TestComponent {
void inject(TestActivity activity);
}