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:在这里它可以提供你要的对象。
可以配合下面的代码理解上面的意思:
Module,Component,Provides
1.创建FragmentComponent:
@Component(modules = FragmentModule.class)public interface FragmentComponent { //它会从Module中查找NewsListFragment中需要的Acitivity实例。找到后交给NewsListFragment。 void inject(NewsListFragment newsListFragment); }
2.创建FragmentModule:
@Modulepublic 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中:@Modulepublic 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上的注解也要替换掉。1234512345
(2)想要实现全局的单例:
(假如我们要在Fragment中获取全局单例对象People)public class People { public People(){} }
a.创建全局单例的Scope:
@Scope@Documented@Retention(RetentionPolicy.RUNTIME)public @interface PerApp {}12341234
b.创建全局AppModule:
@Modulepublic 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:@PerFragment@Component(dependencies = AppComponent.class, modules = FragmentModule.class)public interface FragmentComponent { void inject(NewsListFragment newsListFragment); }
d.在Application的onCreate()方法中初始化AppComponent:
@Overridepublic 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); } }
总结:-->其实之前写这么多代码,都是配置,完事在相应的Fragment或Activity中使用就非常方便了