Dagger2
Google开发的针对android的依赖注入框架,它的设计基于面向对象的一种设计模式(控制反转IOC),最大的特点就是低耦合。
一般依赖注入框架都是通过反射实现,而Dagger2使用编译时生成代码,也就是apt动态生成。这样提高了效率不影响性能。
导入依赖
在Module的build.gradle下添加如下代码:
apply plugin: 'com.neenbedankt.android-apt'
...
dependencies {
...
apt 'com.google.dagger:dagger-compiler:2.4'
compile 'com.google.dagger:dagger:2.4'
compile 'org.glassfish:javax.annotation:10.0-b28'
}
在Project的build.gradle下添加如下代码:
dependencies {
...
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
导入完成Sync一下就可以了。
进入正题
要使用之前要明白各个部分是干嘛的,一头雾水直接用会很不爽。其实看很多项目比如google dagger2-mvp,在Activity或者Fragment中想要实例化对象并不是new一个对象,而是仅仅使用@Inject注解,这个对象就可以直接使用了。而且这个对象想要实现单例并不需要在编写单例设计模式,考虑同步锁之类的代码,其中一系列的操作dagger帮你实现了。这种方式既简单,又解藕还能提高程序员的装x境界..
使用Dagger首先要创建两个部分Component,Module当然还有你自己的对象(比如Fragment)
个人理解:
Component:中介,它帮你联系需要被注入的对象(Module中提供的对象),和要将对象注入给谁(Fragment)。
Module:在这里它可以提供你要的对象。
注意:
一个Component可以包含多个Module,那么它inject的对象就可以使用它所包含的所有Modlue中提供的对象。
一个Component也可以依赖其它的Component,那么它inject的对象可以使用它所依赖的Component中包含的所有Modlue中提供的对象。
可以配合下面的代码理解上面的意思:
Module,Component,Provides
1.创建FragmentComponent:
@Component(modules = FragmentModule.class)
public interface FragmentComponent {
//它会从Module中查找NewsListFragment中需要的Acitivity实例。找到后交给NewsListFragment。
void inject(NewsListFragment newsListFragment);
}
2.创建FragmentModule:
@Module
public class FragmentModule {
private Fragment fragment;
public FragmentModule(Fragment fragment) {
this.fragment = fragment;
}
//这里提供的Activity就可以在Fragment中使用了。
@Provides
Activity provideActivity() {
return fragment.getActivity();
}
}
3.在NewsListFragment相应的位置初始化FragmentComponent:
public class NewsListFragment extends Fragment {
@Inject
Activity activity;
@Inject
User user;//可以看到这个User在Module中并没有提供,那么就去它构造中看看。
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
//这里在创建完Module,Component后要make Project编译一下!
FragmentComponent fragmentComponent = DaggerFragmentComponent.builder()
.fragmentModule(new FragmentModule(this))
.build();
fragmentComponent.inject(this);
return super.onCreateView(inflater, container, savedInstanceState);
}
}
public class User {
//如果Fragment中需要这个实例,而Module中还没有提供该实例化,那么就必须在该对象的构造上加上@Inject注解。
@Inject
public User() {}
}
总结-->
其中的注解:
@Module:提供对象的module必须用它来标注。
@Provides:用于标注提供的对象。(提供的方法名称随意)
@Component:作为中介的一个标注。
@Inject:可以理解为整个过程的起点,最终找的就是它标注下的实例,或者方法。
整个过程就是:
Component将Fragment注入进来,
它会先去Fragment的Module中查找带有@Provides注解的对象,如果找到了Fragment中带有@Inject注解的对象则成功注入,
如果Module中没有找到,去该对象中寻找带有@Inject注解的构造,找到则成功注入,
否则失败。
接下来介绍Dagger中的一些注解:
@Singleton
如果刚才Fragment中的User想要实现单例:
要在FragmentModule中:
@Module
public class FragmentModule {
...
@Provides
@Singleton
User provideUser() {
//这就提供了单例,但是仅限于Fragment生命周期内。
return new User();
}
}
同时FragmentComponent上要添加注解:
@Singleton
@Component(modules = FragmentModule.class)
public interface FragmentComponent {
//它会从Module中查找NewsListFragment中需要的Acitivity实例。找到后交给NewsListFragment。
void inject(NewsListFragment newsListFragment);
}
@Scope
Dagger中的单例可以限制生命周期内单例(整个app生命周期内单例,和Activity或者Fragment生命周期内单例)
所以如果控制整个app生命周期内单例和Activity生命周期内单例,都用@Singleton就造成冲突会出现问题。
-->这时我们可以自定义scope(其实就是有限制的控制单例):
其实@Singleton的实现就是Dagger自定义的scope
@Scope
@Documented
@Retention(RUNTIME)
public @interface Singleton {}
(1)自定义Fragment生命周期内单例:
@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface PerFragment {}
将刚才的FragmentModule中的单例注解替换为@PerFragment即可,FragmentComponent上的注解也要替换掉。
(2)想要实现全局的单例:
(假如我们要在Fragment中获取全局单例对象People)
public class People {
public People(){}
}
a.创建全局单例的Scope:
@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface PerApp {}
b.创建全局AppModule:
@Module
public class AppModule {
private final Context context;
public AppModule(Context context) {
this.context = context;
}
@Provides
Context provideContext() {
return context;
}
//↓↓↓这里提供的对象可以在依赖AppComponent的所有Component注入的对象中使用
// 比如(ActivityComponent,FragmentComponent中inject的对象)
// 自然这里限制的单例,全局有效。
@Provides
@PerApplication
People proPeople() {
return new People();
}
}
c.创建全局AppComponent:
@PerApplication
@Component(modules = AppModule.class)
public interface AppComponent {
//它的特点是,需要提供AppModule中提供好的对象
Context getContext();//方法名随意
People getPeople();
}
注意:刚才的FragmentComponent要依赖全局的APPComponent:
当然因为依赖了AppComponent,就可以给inject()的对象提供AppModlue中的对象了。
@PerFragment
@Component(dependencies = AppComponent.class, modules = FragmentModule.class)
public interface FragmentComponent {
void inject(NewsListFragment newsListFragment);
}
d.在Application的onCreate()方法中初始化AppComponent:
@Override
public void onCreate() {
super.onCreate();
appComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.build();
}
e.在Fragment中获取FragmentComponent:
public class NewsListFragment extends Fragment {
@Inject
Activity activity;
@Inject
User user;
@Inject
People people;//这个people就是全局单例。
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
FragmentComponent fragmentComponent = DaggerFragmentComponent.builder()
.appComponent(appComponent//app中初始化好的)
.fragmentModule(new FragmentModule(this))
.build();
fragmentComponent.inject(this);
return super.onCreateView(inflater, container, savedInstanceState);
}
}
总结:dagger2不易上手,需要自己多练习,因为一些坑只有实践过才知道。
其实本人也是初学者,看过很多的文档,只能算是会使用了。写下来分享给需要的朋友。有兴趣的可以参照本人github的A News Demo如有问题,欢迎指正。
7993

被折叠的 条评论
为什么被折叠?



