热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Dagger2在Android上的使用(六)

本文对系列的第一篇文章中的例子进行了分析总结。本文首发:http:yuweiguocn.github.io《天净沙·秋思》枯藤老树昏鸦,小桥流水人家,古道西风瘦马。夕阳西下,断肠人

本文对系列的第一篇文章中的例子进行了分析总结。

本文首发:http://yuweiguocn.github.io/

《天净沙·秋思》
枯藤老树昏鸦,小桥流水人家,古道西风瘦马。
夕阳西下,断肠人在天涯。
-元代,马致远

Dagger 2 在 Android 上的使用(一)
Dagger 2 在 Android 上的使用(二)
Dagger 2 在 Android 上的使用(三)
Dagger 2 在 Android 上的使用(四)
Dagger 2 在 Android 上的使用(五)

前言

在前面的文章我们介绍了Dagger2 中的大部分注解的使用,接下来我们从源码角度分析下第一篇文章中例子的原理。

AppComponent

自定义组件AppComponent继承了AndroidInjector接口类,指定了Module类ActivityBindingModule和Dagger2中的AndroidSupportInjectionModule:

@Component(modules = {ActivityBindingModule.class,AndroidSupportInjectionModule.class})
public interface AppComponent extends AndroidInjector {
}

AndroidInjector接口中包含一个inject用于注入的方法,和一个抽象Builder类,其中用到了我们在上文中介绍的@BindsInstance注解,用于将注入的实例绑定到构建的依赖图中。

public interface AndroidInjector {
void inject(T instance);
interface Factory {
AndroidInjector create(T instance);
}
abstract class Builder implements AndroidInjector.Factory {
@Override
public final AndroidInjector create(T instance) {
seedInstance(instance);
return build();
}
@BindsInstance
public abstract void seedInstance(T instance);
public abstract AndroidInjector build();
}
}

AndroidSupportInjectionModule中用@Multibinds注解声明了Support中Fragment的多绑定,包括Fragment的Class的key和String的key两个集合,还用到了@Moduleincludes属性用于引入其它的Module进行组合:

@Beta
@Module(includes = AndroidInjectionModule.class)
public abstract class AndroidSupportInjectionModule {
@Multibinds
abstract Map, AndroidInjector.Factory>
supportFragmentInjectorFactories();
@Multibinds
abstract Map>
supportFragmentInjectorFactoriesWithStringKeys();
private AndroidSupportInjectionModule() {}
}

AndroidInjectionModule类中和AndroidSupportInjectionModule类似,声明了Android中四大组件Activity、Service、BroadcastReceiver、ContentProvider和Fragment的多绑定,只所以需要声明是由于这些Map集合有可能为空

@Beta
@Module
public abstract class AndroidInjectionModule {
@Multibinds
abstract Map, AndroidInjector.Factory>
activityInjectorFactories();
@Multibinds
abstract Map>
activityInjectorFactoriesWithStringKeys();
@Multibinds
abstract Map, AndroidInjector.Factory>
fragmentInjectorFactories();
@Multibinds
abstract Map>
fragmentInjectorFactoriesWithStringKeys();
@Multibinds
abstract Map, AndroidInjector.Factory>
serviceInjectorFactories();
@Multibinds
abstract Map>
serviceInjectorFactoriesWithStringKeys();
@Multibinds
abstract Map<
Class, AndroidInjector.Factory>
broadcastReceiverInjectorFactories();
@Multibinds
abstract Map>
broadcastReceiverInjectorFactoriesWithStringKeys();
@Multibinds
abstract Map, AndroidInjector.Factory>
contentProviderInjectorFactories();
@Multibinds
abstract Map>
contentProviderInjectorFactoriesWithStringKeys();
private AndroidInjectionModule() {}
}

ActivityBindingModule

下面是我们自定义的用于Activity绑定的Module类:

@Module
public abstract class ActivityBindingModule {
@ActivityScope
@ContributesAndroidInjector(modules = HomeModule.class)
abstract HomeActivity contributeHomeActivity();
}

注解@ContributesAndroidInjector用于为该方法返回类型生成一个AndroidInjector。用在Module中的无参抽象方法上,返回参数为具体的Android框架类型(如:HomeActivity、MyFragment、MyService等),指定的Module将会被安装到生成的Subcomponent上。上面的代码将会生成下面的类:

@Module(subcompOnents= ActivityBindingModule_ContributeHomeActivity.HomeActivitySubcomponent.class)
public abstract class ActivityBindingModule_ContributeHomeActivity {
private ActivityBindingModule_ContributeHomeActivity() {}
@Binds
@IntoMap
@ActivityKey(HomeActivity.class)
abstract AndroidInjector.Factory bindAndroidInjectorFactory(
HomeActivitySubcomponent.Builder builder);
@Subcomponent(modules = HomeModule.class)
@ActivityScope
public interface HomeActivitySubcomponent extends AndroidInjector {
@Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder {}
}
}

这里使用了多绑定以Activity的class为key和生成的子组件的Builder类为value绑定到了Map集合中。

DaggerAppComponent

上面类中的多绑定会在生成的Component类中生成提供该集合的方法,以及生成的子组件接口的实现类:

public final class DaggerAppComponent implements AppComponent {
private Provider
homeActivitySubcomponentBuilderProvider;
private DaggerAppComponent(Builder builder) {
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
public static AppComponent create() {
return new Builder().build();
}
private Map, Provider>>
getMapOfClassOfAndProviderOfFactoryOf() {
return MapBuilder
., Provider>>
newMapBuilder(1)
.put(HomeActivity.class, (Provider) homeActivitySubcomponentBuilderProvider)
.build();
}
private DispatchingAndroidInjector getDispatchingAndroidInjectorOfActivity() {
return DispatchingAndroidInjector_Factory.newDispatchingAndroidInjector(
getMapOfClassOfAndProviderOfFactoryOf(),
Collections.>>emptyMap());
}
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.homeActivitySubcompOnentBuilderProvider=
new Provider<
ActivityBindingModule_ContributeHomeActivity.HomeActivitySubcomponent.Builder>() {
@Override
public ActivityBindingModule_ContributeHomeActivity.HomeActivitySubcomponent.Builder
get() {
return new HomeActivitySubcomponentBuilder();
}
};
}
@Override
public void inject(App arg0) {
injectApp(arg0);
}
private App injectApp(App instance) {
DaggerApplication_MembersInjector.injectActivityInjector(
instance, getDispatchingAndroidInjectorOfActivity());
return instance;
}
public static final class Builder {
private Builder() {}
public AppComponent build() {
return new DaggerAppComponent(this);
}
}
private final class HomeActivitySubcomponentBuilder
extends ActivityBindingModule_ContributeHomeActivity.HomeActivitySubcomponent.Builder {
private HomeActivity seedInstance;
@Override
public ActivityBindingModule_ContributeHomeActivity.HomeActivitySubcomponent build() {
if (seedInstance == null) {
throw new IllegalStateException(HomeActivity.class.getCanonicalName() + " must be set");
}
return new HomeActivitySubcomponentImpl(this);
}
@Override
public void seedInstance(HomeActivity arg0) {
this.seedInstance = Preconditions.checkNotNull(arg0);
}
}
private final class HomeActivitySubcomponentImpl
implements ActivityBindingModule_ContributeHomeActivity.HomeActivitySubcomponent {
private Provider bindPresenterProvider;
private HomeActivitySubcomponentImpl(HomeActivitySubcomponentBuilder builder) {
initialize(builder);
}
@SuppressWarnings("unchecked")
private void initialize(final HomeActivitySubcomponentBuilder builder) {
this.bindPresenterProvider = DoubleCheck.provider((Provider) HomePresenter_Factory.create());
}
@Override
public void inject(HomeActivity arg0) {
injectHomeActivity(arg0);
}
private HomeActivity injectHomeActivity(HomeActivity instance) {
DaggerActivity_MembersInjector.injectFragmentInjector(
instance, DaggerAppComponent.this.getDispatchingAndroidInjectorOfFragment());
HomeActivity_MembersInjector.injectMPresenter(instance, bindPresenterProvider.get());
return instance;
}
}
}

DaggerApplication

我们在Application中继承了DaggerApplication类,并实现了applicationInjector方法返回了AppComponent类的实例:

public class App extends DaggerApplication {
@Override
protected AndroidInjector applicationInjector() {
return DaggerAppComponent.create();
}
}

DaggerApplication在onCreate方法中调用了我们实现的applicationInjector方法,然后调用inject方法完成了对成员变量的注入。

@Beta
public abstract class DaggerApplication extends Application
implements HasActivityInjector,
HasFragmentInjector,
HasServiceInjector,
HasBroadcastReceiverInjector,
HasContentProviderInjector {
@Inject DispatchingAndroidInjector activityInjector;
@Inject DispatchingAndroidInjector broadcastReceiverInjector;
@Inject DispatchingAndroidInjector fragmentInjector;
@Inject DispatchingAndroidInjector serviceInjector;
@Inject DispatchingAndroidInjector contentProviderInjector;
private volatile boolean needToInject = true;
@Override
public void onCreate() {
super.onCreate();
injectIfNecessary();
}
@ForOverride
protected abstract AndroidInjector applicationInjector();
private void injectIfNecessary() {
if (needToInject) {
synchronized (this) {
if (needToInject) {
@SuppressWarnings("unchecked")
AndroidInjector applicatiOnInjector=
(AndroidInjector) applicationInjector();
applicationInjector.inject(this);
if (needToInject) {
throw new IllegalStateException(
"The AndroidInjector returned from applicationInjector() did not inject the "
+ "DaggerApplication");
}
}
}
}
}
@Inject
void setInjected() {
needToInject = false;
}
@Override
public DispatchingAndroidInjector activityInjector() {
return activityInjector;
}
@Override
public DispatchingAndroidInjector fragmentInjector() {
return fragmentInjector;
}
@Override
public DispatchingAndroidInjector broadcastReceiverInjector() {
return broadcastReceiverInjector;
}
@Override
public DispatchingAndroidInjector serviceInjector() {
return serviceInjector;
}
@Override
public AndroidInjector contentProviderInjector() {
injectIfNecessary();
return contentProviderInjector;
}
}

DaggerActivity

我们的Activity继承自了DaggerActivity,DaggerActivity类中实现HasFragmentInjector接口用于Fragment的注入,在onCreate方法中使用AndroidInjection类完成了Activity中所需的依赖注入。

@Beta
public abstract class DaggerActivity extends Activity implements HasFragmentInjector {
@Inject DispatchingAndroidInjector fragmentInjector;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
}
@Override
public AndroidInjector fragmentInjector() {
return fragmentInjector;
}
}

AndroidInjection

AndroidInjection是一个工具类,用于对Android框架中Activity、Fragment、Service、BroadcastReceiver、ContentProvider进行依赖注入。AndroidInjection会从Application中获取activityInjector方法的值进行依赖注入。

public final class AndroidInjection {
private static final String TAG = "dagger.android";
public static void inject(Activity activity) {
checkNotNull(activity, "activity");
Application application = activity.getApplication();
if (!(application instanceof HasActivityInjector)) {
throw new RuntimeException(
String.format(
"%s does not implement %s",
application.getClass().getCanonicalName(),
HasActivityInjector.class.getCanonicalName()));
}
AndroidInjector activityInjector =
((HasActivityInjector) application).activityInjector();
checkNotNull(activityInjector, "%s.activityInjector() returned null", application.getClass());
activityInjector.inject(activity);
}
...
private AndroidInjection() {}
}

DispatchingAndroidInjector

DaggerApplication中activityInjector方法返回的是DispatchingAndroidInjector类型,DispatchingAndroidInjector用于Android框架类型实例的成员变量的注入,首先对构造方法传入的两个集合进行了合并,然后在注入时根据类名从集合中获取对应实现类完成成员变量的注入。

public final class DispatchingAndroidInjector implements AndroidInjector {
private static final String NO_SUPERTYPES_BOUND_FORMAT =
"No injector factory bound for Class<%s>";
private static final String SUPERTYPES_BOUND_FORMAT =
"No injector factory bound for Class<%1$s>. Injector factories were bound for supertypes "
+ "of %1$s: %2$s. Did you mean to bind an injector factory for the subtype?";
private final Map>> injectorFactories;
@Inject
DispatchingAndroidInjector(
Map, Provider>> injectorFactoriesWithClassKeys,
Map>> injectorFactoriesWithStringKeys) {
this.injectorFactories = merge(injectorFactoriesWithClassKeys, injectorFactoriesWithStringKeys);
}
private static Map merge(
Map, V> classKeyedMap, Map stringKeyedMap) {
if (classKeyedMap.isEmpty()) {
return stringKeyedMap;
}
Map merged =
newLinkedHashMapWithExpectedSize(classKeyedMap.size() + stringKeyedMap.size());
merged.putAll(stringKeyedMap);
for (Entry, V> entry : classKeyedMap.entrySet()) {
merged.put(entry.getKey().getName(), entry.getValue());
}
return Collections.unmodifiableMap(merged);
}
@CanIgnoreReturnValue
public boolean maybeInject(T instance) {
Provider> factoryProvider =
injectorFactories.get(instance.getClass().getName());
if (factoryProvider == null) {
return false;
}
@SuppressWarnings("unchecked")
AndroidInjector.Factory factory = (AndroidInjector.Factory) factoryProvider.get();
try {
AndroidInjector injector =
checkNotNull(
factory.create(instance), "%s.create(I) should not return null.", factory.getClass());
injector.inject(instance);
return true;
} catch (ClassCastException e) {
throw new InvalidInjectorBindingException(
String.format(
"%s does not implement AndroidInjector.Factory<%s>",
factory.getClass().getCanonicalName(), instance.getClass().getCanonicalName()),
e);
}
}
@Override
public void inject(T instance) {
boolean wasInjected = maybeInject(instance);
if (!wasInjected) {
throw new IllegalArgumentException(errorMessageSuggestions(instance));
}
}
@Beta
public static final class InvalidInjectorBindingException extends RuntimeException {
InvalidInjectorBindingException(String message, ClassCastException cause) {
super(message, cause);
}
}
private String errorMessageSuggestions(T instance) {
List suggestiOns= new ArrayList<>();
for (Class clazz = instance.getClass(); clazz != null; clazz = clazz.getSuperclass()) {
if (injectorFactories.containsKey(clazz.getCanonicalName())) {
suggestions.add(clazz.getCanonicalName());
}
}
return suggestions.isEmpty()
? String.format(NO_SUPERTYPES_BOUND_FORMAT, instance.getClass().getCanonicalName())
: String.format(
SUPERTYPES_BOUND_FORMAT, instance.getClass().getCanonicalName(), suggestions);
}
}

总结

Dagger2使用多绑定和子组件功能将需要成员变量注入类的class和生成子组件实现类存入到Application的Map集合中,在Activity#onCreate方法中通过类名从Map集合中获取对应实现类完成了成员变量注入。

参考

  • https://google.github.io/dagger/
  • https://www.jianshu.com/p/24af4c102f62
  • http://www.cnblogs.com/tiantianbyconan/p/5092083.html

推荐阅读
  • 本文介绍了在go语言中利用(*interface{})(nil)传递参数类型的原理及应用。通过分析Martini框架中的injector类型的声明,解释了values映射表的作用以及parent Injector的含义。同时,讨论了该技术在实际开发中的应用场景。 ... [详细]
  • 1.在gradle中添加依赖在主项目的build.gradle中添加Dagger2库的依赖dependencies{compilecom.google.dagger:dagger: ... [详细]
  • dagger2简单使用与理解笔记
    文章目录使用dagger2好处具体案例查看github1.使用dagger2注入基本使用流程概念2.dagger2中各种注解基本使用引入dagger20.写两个对象用来实际操作的1 ... [详细]
  • RxCache是使用注解为Retrofit加入二级缓存(内存,磁盘)的缓存库。开头膜拜大神项目地址:RxCacheRxCache使用方法定义接口publicinterfaceCac ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • Dagger 2 系列(二) 基础篇:基本功能的实现
    Dagger2该系列博客的最终目标:搭建MVP+Dagger2框架该系列博客包含以下几篇内容:Dagger2系列(一)—前奏篇:基本概念介绍Dagger2系列(二)—基础篇:基本功 ... [详细]
  • #前言AndroidArchitectureComponents是谷歌在GoogleIO2017发布的。官方的描述:https:developer.android.google.c ... [详细]
  • 开发笔记:Dagger2 探索记3——两大进阶组件
        今天要讲的时@Scope这个组件。为什么说它是进阶组件,就是因为它基本上没作用,但在理解了基本组件之后又必须用到。 ... [详细]
  • android 自定义模板下载,android studio 自定义模板
    由于项目用上了mvp架构,基本上一个页面就至少需要新创建6个类,分别是modelviewpresenter的接口以及其对应的实现类,再加上使用dagger的话就要更多了,所以这时候 ... [详细]
  • Uberlicenseforandroidlist:1.ButterKnife:项目地址:https:github.comJakeWhartonbutterknife这个开源库可以 ... [详细]
  • Android Studio中使用apt
    AndroidStudio中使用apt一、前言你还在对着枯燥的重复代码一味复制粘贴吗?这样跟搬砖有何区别?你是否曾想过:你用代码编写出一个自动化的APP,但为何代码本身却缺少了活力 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
author-avatar
Idi-amin_643
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有