Dagger2 Android --- 注解&注入流程分析篇

Dagger2 Android --- 注解&注入流程分析篇

本篇的分析基于前一篇基础使用:

Dagger2 Android --- 基础使用篇

注解分析

上一篇我们知道使用Dagger Android有这几个步骤:

  1. 自定义Application继承DaggerApplication
  2. 创建MainComponent
  3. 创建ActivityBindingModule,SubComponent为MainComponent
  4. 创建AppComponent,modules为AndroidSupportInjectionModule.class,ActivityBindingModule.class
  5. make project,将生成的DaggerAppComponent传给自定义Application
  6. 在MainActivity的onCreate中,使用AndroidInjection.inject(this)实现注入,实现了对象的绑定(也可以让activity继承DaggerActivity,省略这步)

#自定义Application继承DaggerApplication

DemoApp代码:

public class DemoApp extends DaggerApplication {

    @Override
    protected AndroidInjector applicationInjector() {
        //需要返回DaggerAppComponent给DaggerApplication
        return DaggerAppComponent.builder().create(this);
        
    }
}

这一步没有使用任何注解:重点都在DaggerApplication中。那我们就关注下这个类做了什么事情。

DaggerApplication源码:

@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;
  }

  ...
}

源码主要做了两件事:

  • 提供四大组件及Fragment的注解分发器:DispatchingAndroidInjector
  • 在onCreate时,且需要注入时,调用applicationInjector.inject(this);实现注入

那applicationInjector是什么时候创建的呢?

@ForOverride
protected abstract AndroidInjector applicationInjector();

在我们继承DaggerApplication会默认实现该方法,并且将实现了AndroidInjector接口的类返回给父类。

那实现了AndroidInjector接口的类 又是什么时候生成的呢?

这个问题先放一放,稍后分析,我们看第二步

MainComponent

模板代码,泛型为需要注入的类:

@Subcomponent
public interface MainComponent extends AndroidInjector {

    @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder{}

}

这边用到了两个注解:

  1. SubComponent

    使用SubComponet是为了继承父类的依赖图,父类中使用注解提供依赖的对象,在MainComponent中,同样可以使用。

    同时会生成XXXComponentImpl的final类

     private final class MainComponentImpl implements MainComponent {
       private MainComponentImpl(MainComponentBuilder builder) {}
    
       @Override
       public void inject(MainActivity arg0) {
         injectMainActivity(arg0);
       }
    
       private MainActivity injectMainActivity(MainActivity instance) {
         DaggerAppCompatActivity_MembersInjector.injectSupportFragmentInjector(
             instance, DaggerAppComponent.this.getDispatchingAndroidInjectorOfFragment2());
         DaggerAppCompatActivity_MembersInjector.injectFrameworkFragmentInjector(
             instance, DaggerAppComponent.this.getDispatchingAndroidInjectorOfFragment());
         MainActivity_MembersInjector.injectStudent(instance, new Student());
         return instance;
       }
     }
    

    该类中,会通过inject方法将MainActivityStudent对象进行绑定,将Student注入到MainActivity中。

    我们还可以看到,除了注入了Student之外,还注入了Fragment和SupportFragment。

  2. SubComponent.Builder

    使用了该注解,会生成XXXComponentBuilder的final类,

    private final class MainComponentBuilder extends MainComponent.Builder {
      private MainActivity seedInstance;
    
      @Override
      public MainComponent build() {
        if (seedInstance == null) {
          throw new IllegalStateException(MainActivity.class.getCanonicalName() + " must be set");
        }
        return new MainComponentImpl(this);
      }
    
      @Override
      public void seedInstance(MainActivity arg0) {
        this.seedInstance = Preconditions.checkNotNull(arg0);
      }
    }
    

    这个类比较重要,其中持有了MainActivity实例。

    通过seedInstance传入MainActivity,同时通过build创建MainComponentImpl,这样MainComponentImpl也就拥有了MainActivity实例。

    那么seedInstance又是在什么地方调用的呢?

  3. AndroidInjector

    MainComponentImpl实现了MainComponentMainComponentBuilder又继承了抽象类MainComponent.Builder

    是不是有点眼熟,对!就是我们刚才创建的MainComponent。MainComponent又继承了AndroidInjector接口。

    我们再看下MainComponent代码:

     @Subcomponent
     public interface MainComponent extends AndroidInjector {
     
         @Subcomponent.Builder
         abstract class Builder extends AndroidInjector.Builder{}
     
     }
    

    所以先看AndroidInjector源码:

     @Beta
     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();
       }
     }
    

    定义了一个inject方法实现注入;一个工厂类,用来创建该对象。这里就是Dagger2 Android的核心了:面向接口编程,移除被注入者对注入者的依赖

    这里通过调用create传入需要的目标对象,并通过seedInstance设置,然后再调用build方法。

    因为 MainComponentBuilder 继承了 Factory,所有也就是调用其内部的build方法,build做了什么事?? --> 可以翻到上面看看

    这边用到一个比较重要的注解: @BindsInstance

    添加了该注解的方法,会默认在子类里面生成一个 T类型的对象,同时在 seedInstance 方法里面进行复制

     private final class MainComponentBuilder extends MainComponent.Builder {
       private MainActivity seedInstance;
       ...
    
       @Override
       public void seedInstance(MainActivity arg0) {
         this.seedInstance = Preconditions.checkNotNull(arg0);
       }
     }
    

    这两块代码就是通过该注解实现的。现在再来通过这张图梳理一下:

Dagger2 Android --- 注解&注入流程分析篇_第1张图片
image

创建ActivityBindingModule

还是先看下代码:

@Module(subcomponents = {MainComponent.class})
public abstract class ActivityBindingModule {

    @Binds
    @IntoMap
    @ActivityKey(MainActivity.class)
    abstract AndroidInjector.Factory bindMainActivityInjectorFactory(MainComponent.Builder builder);
    
}

这边用到了5个注解:

  • Module,subcomponents:这两个应该都知道了
  • Binds:比较重要的一个注解,告诉dagger,参数是实现了AndroidInjector.Factory接口的类,生成代码的时候会去遍历添加了Inject注解的类,查看是否实现了该接口,然后动态生成;当然也可以通过@Providers和new实现
  • IntoMap,ActivityKey:这两个是配对使用的,意思就是将生成的MainComponent.Builder对象放入到Map中,key为ActivityKey(除了ActivityKey,还有StringKey、booleanKey等等)

这一步的作用就是统一管理注入 Builder 类。

下面我们看下生成的代码,验证下刚才的分析:

public final class DaggerAppComponent implements AppComponent {
  private Provider mainComponentBuilderProvider;

    ... 
  
    private Map, Provider>>
        getMapOfClassOfAndProviderOfFactoryOf() {
      return Collections
          ., Provider>>
              singletonMap(MainActivity.class, (Provider) mainComponentBuilderProvider);
    }
  
   ...
 }

确实如此:

使用Binds最终也是通过Provider提供的对象,然后再存入MapBuilder中,等待后续使用。

AppComponent类

AppComponent类:

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

    @Component.Builder
    abstract class Builder extends AndroidInjector.Builder {

    }
}

这边有个AndroidSupportInjectionModule,继承自AndroidInjectionModule,这个是干嘛用的呢?

AndroidInjectionModule源码:

@Beta
@Module
public abstract class AndroidInjectionModule {
  @Multibinds
  abstract Map, AndroidInjector.Factory>
      activityInjectorFactories();

  @Multibinds
  abstract Map, AndroidInjector.Factory>
      fragmentInjectorFactories();

  @Multibinds
  abstract Map, AndroidInjector.Factory>
      serviceInjectorFactories();

  @Multibinds
  abstract Map<
          Class, AndroidInjector.Factory>
      broadcastReceiverInjectorFactories();

  @Multibinds
  abstract Map<
          Class, AndroidInjector.Factory>
      contentProviderInjectorFactories();

  private AndroidInjectionModule() {}
}

又有点熟悉了,和我们刚才分析的ActivityBindingModule有点类似。

这个module的作用:

  1. 通过ActivityBindingModule生成并保存了所有的AcitivtyBuilder到Map中
  2. 然后通过这个module将Map提供给AppComponent

再来看下生成的DaggerAppComponent:

public final class DaggerAppComponent implements AppComponent {
  private Provider mainComponentBuilderProvider;

  private DaggerAppComponent(Builder builder) {
    initialize(builder);
  }

  public static AppComponent.Builder builder() {
    return new Builder();
  }

    private Map, Provider>>
        getMapOfClassOfAndProviderOfFactoryOf() {
      return Collections
          ., Provider>>
              singletonMap(MainActivity.class, (Provider) mainComponentBuilderProvider);
    }

  private DispatchingAndroidInjector getDispatchingAndroidInjectorOfActivity() {
    return DispatchingAndroidInjector_Factory.newDispatchingAndroidInjector(
        getMapOfClassOfAndProviderOfFactoryOf());
  }

  ...
  
  private DispatchingAndroidInjector
      getDispatchingAndroidInjectorOfFragment2() {
    return DispatchingAndroidInjector_Factory.newDispatchingAndroidInjector(
        Collections
            .,
                Provider>>
                emptyMap());
  }

  @SuppressWarnings("unchecked")
  private void initialize(final Builder builder) {
    this.mainComponentBuilderProvider =
        new Provider() {
          @Override
          public MainComponent.Builder get() {
            return new MainComponentBuilder();
          }
        };
  }

  @Override
  public void inject(DemoApp arg0) {
    injectDemoApp(arg0);
  }

  private DemoApp injectDemoApp(DemoApp instance) {
    DaggerApplication_MembersInjector.injectActivityInjector(
        instance, getDispatchingAndroidInjectorOfActivity());
    ...
    return instance;
  }

  private static final class Builder extends AppComponent.Builder {
    private DemoApp seedInstance;

    @Override
    public AppComponent build() {
      if (seedInstance == null) {
        throw new IllegalStateException(DemoApp.class.getCanonicalName() + " must be set");
      }
      return new DaggerAppComponent(this);
    }

    @Override
    public void seedInstance(DemoApp arg0) {
      this.seedInstance = Preconditions.checkNotNull(arg0);
    }
  }

  private final class MainComponentBuilder extends MainComponent.Builder {
    ...
  }

  private final class MainComponentImpl implements MainComponent {
    ...
  }
}

代码有点多,所有我们就从入口开始看:

DaggerAppComponent.builder().create(this);

builder().create(),还记得上面的图吗,注入模板类就是通过这个调用生成的。

一步一步看create的执行流程,可以看到两行关键代码:

  • new DaggerAppComponent(this);
  • new MainComponentBuilder();

到这边,所有的依赖图谱都已经构建完成。

注入的最终实现 inject

1. 注入到DemoApp
AndroidInjector 中inject方法的调用

@Beta
public abstract class DaggerApplication extends Application
    implements HasActivityInjector,
        HasFragmentInjector,
        HasServiceInjector,
        HasBroadcastReceiverInjector,
        HasContentProviderInjector {

  ...

  @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");
          }
        }
      }
    }
  }
}

applicationInjector对象的生成:

public class DemoApp extends DaggerApplication {

    @Override
    protected AndroidInjector applicationInjector() {
        return DaggerAppComponent.builder().create(this);
    }
}

还记得之前的疑问吗,AndroidInjector 对象就是在这里创建的。

在DaggerApplication内部可以看到,如果需要注入,就会执行applicationInjector.inject(this)方法;而DaggerAppComponent正式实现了AndroidInjector的类,却在create的时候已经创建。

2. 注入到MainActivity

调用AndroidInjection.inject(this);

public class MainActivity extends DaggerAppCompatActivity {

    @Inject
    Student student;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        AndroidInjection.inject(this);
        setContentView(R.layout.activity_main);
    }
}

AndroidInjection:

@Beta
public final class AndroidInjection {
  ...

  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);
  }
}

最终也是通过AndroidInjector 的 inject 方法实现注入,

同样在create的时候,已经创建了MainComponentBuilderMainComponentBuilder内部又会创建MainComponentImpl,而MainComponentImpl正是实现了AndroidInjector的类。

所有这里的activityInjector对象肯定是存在的,整个注入流程也就实现了。

流程梳理

可以看出,Dagger Android实现自动注入主要分为两部分:

  1. 注入代码的生成、依赖图谱的构建

     @Beta
     public interface AndroidInjector {
     
       ...
       
       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();
       }
    

    }

    通过抽象类约束生成Dagger注入模板代码,在Application中调用create的时候,会解析依赖图谱并生成所有的注入模板代码

  1. 注入的实现

     @Beta
     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();
       }
     }
    

    通过调用inject传入需要使用的对象。

新注解使用

Dagger Android虽然说实现了解耦,但是步骤实在太繁琐了。

所以在2.11之后,有了@ContributesAndroidInjector注解

新建了一个Module类,声明需要被注入的Activity:

@Module
public abstract class NewActivityBindingModule {

    @ContributesAndroidInjector(modules = MainModule.class)
    abstract MainActivity mainActivity();

    @ContributesAndroidInjector
    abstract DetailActivity detailActivity();
}

替换AppComponent里面的modules:

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

    @Component.Builder
    abstract class Builder extends AndroidInjector.Builder {

    }
}

对! 就这么简单,没有了MainComponent,没有了@Binds...,一个注解就帮我们做到了。

make project:

生成了两个ActivityBinding_Module类:

Dagger2 Android --- 注解&注入流程分析篇_第2张图片
image

这个类里面又帮我们把重复工作做掉了,尽可能减少使用者的麻烦

@Module(subcomponents = NewActivityBindingModule_DetailActivity.DetailActivitySubcomponent.class)
public abstract class NewActivityBindingModule_DetailActivity {
  private NewActivityBindingModule_DetailActivity() {}

  @Binds
  @IntoMap
  @ActivityKey(DetailActivity.class)
  abstract AndroidInjector.Factory bindAndroidInjectorFactory(
      DetailActivitySubcomponent.Builder builder);

  @Subcomponent
  public interface DetailActivitySubcomponent extends AndroidInjector {
    @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder {}
  }
}

你可能感兴趣的:(Dagger2 Android --- 注解&注入流程分析篇)