看完不懂Dagger2我跪搓板

作者: 付凯强 | 来源:发表于2018-11-30 15:09 被阅读118次

    0. 序言

    • 有些人说现在的架构都是Mvp+Dagger2,其实好多公司还是没有用Dagger2,因为项目的更新换代不是一天就能完成的,公司项目需要的终极目标其实是稳定,就算你不用Dagger2,依然可以实现预期的效果。但是使用了Dagger2的项目,代码层面解耦更好,所以Dagger2是每个Android开发都应该熟练掌握的,就像Java后台开发熟练掌握Spring一样。
    • 博文主要分为三大部分:注解、懒加载和原理分析。注解包括:
    ① @Inject 和 @Component
    ② @Module 和 @Provides
    ③ @Named 和 @Qualifier
    ④ @Singleton和@Scope
    ⑤ @Component的dependencies
    

    1. 所涉及依赖:

        annotationProcessor 'com.google.dagger:dagger-compiler:2.7'
        implementation 'com.google.dagger:dagger:2.7'
        implementation 'com.google.code.gson:gson:2.8.5'
    

    2. @Inject 和 @Component

    • 定义两个类,分别是MainActivity和Person,并在MainActivity中执行Person的eat方法
    public class Person{
        public void eat(){
            Log.i("fukq","我要吃面包");
        }
    }
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Person person = new Person();
            person.eat();
        }
    }
    
    11-27 14:47:51.695 32317-32317/com.smartisan.dagger2 I/fukq: 我要吃面包
    
    • 用Dagger2改造以上示例:

    2.1. 改写Person类:

    public class Person{
        @Inject
        public Person() {
        }
    
        public void eat(){
            Log.i("fukq","我要吃面包");
        }
    }
    

    说明:这里标记Person构造方法,则表明Dagger2可以使用Person构造方法构建对象。

    2.2. 创建接口MainActivityComponent指定依赖注入的目标类:

    @Component
    public interface MainActivityComponent {
        void inject(MainActivity activity);
    }
    

    说明:
    ① 接口命令建议:目标类名+Component。
    ② @Component 就是告诉Dagger2依赖注入的目标是MainActivity。
    ③ 创建完接口后记得编译下:锤子按钮(AndroidStudio)。这样在编译后Dagger2就会为我们生成名为Dagger+目标类名+Component的辅助类,辅助类的默认生成路径如下:


    image.png

    2.3. 在目标类MainActivity中使用辅助类DaggerMainActivityComponent完成注入:

    public class MainActivity extends AppCompatActivity {
        @Inject
        Person mPerson; // 1
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            DaggerMainActivityComponent.create().inject(this); // 2
            mPerson.eat();
        }
    }
    

    说明:
    ① Inject用来标记需要注入的实例,这个实例是以成员变量的形式出现。
    ② 辅助类DaggerMainActivityComponent调用inject完成注入。
    ③ 总结可知:Inject有三种注入方式,分别是成员变量注入和构造方法注入以及方法注入(后面会讲)。

    11-27 14:57:24.679 32691-32691/com.smartisan.dagger2 I/fukq: 我要吃面包
    

    3. @Module 和 @Provides

    3.1 Dagger2引入第三方类库

    如果项目使用第三方的类库,比如Gson,我们就不能把@Inject添加到Gson的构造方法中,这个时候采用@Module和@Provides来处理。

    3.1.1. 创建GsonModule类:

    @Module
    public class GsonModule {
    
        @Provides
        public Gson provideGson(){
            return new Gson();
        }
    }
    

    说明:
    ① @Module用来告诉Component,可以从这个类获取依赖对象。
    ② 告诉了对象所在的类,还需要告诉Component获取依赖对象实例的方法,所以用@Provides注释方法。

    3.1.2. 编写Component类MainActivityComponent:

    @Component(modules = GsonModule.class)
    public interface MainActivityComponent {
        void inject(MainActivity activity);
    }
    

    说明:
    ① 之前已经创建了MainActivityComponent类,添加modules = GsonModule.class即可
    ② modules = GsonModule.class用来指定module,之所以用modules,是因为可以指定多个Module.

    3.1.3. 在MainActivity中使用Gson:

    public class MainActivity extends AppCompatActivity {
        @Inject
        Gson mGson;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            DaggerMainActivityComponent.create().inject(this);
    
            String jsonData = "{'name':'fukq','age':18}";
            Man man = mGson.fromJson(jsonData,Man.class);
            Log.i("fukq","name-------"+man.getName());
        }
    }
    
    public class Man{
        private String name;
        private int age;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    }
    
    11-27 16:36:54.512 3275-3275/com.smartisan.dagger2 I/fukq: name-------fukq
    
    3.2 Dagger2引入抽象对象

    除了第三方仓库的引入不能使用@Inject,如果注入的对象是抽象的,那么@Inject也无法使用,因为抽象的类并不能实例化。比如:

    public abstract class Engine {
        public abstract String work();
    }
    
    public class GasolineEngline extends Engine {
        @Inject
        public GasolineEngline() {
        }
    
        @Override
        public String work() {
            return "汽油发动机发动";
        }
    }
    
    public class Car {
        private Engine mEngine;
    
        @Inject
        public Car(Engine engine) {
            mEngine = engine;
        }
        public String run(){
            return mEngine.work();
        }
    }
    

    说明:这里用的Inject的构造方法注入。可能你会问哪种注入方式更好呢,这里建议构造方法注入,以后会专门拿出一篇文章来讲解这个事情。

    public class MainActivity extends AppCompatActivity {
        @Inject
        Person mPerson;
        @Inject
        Gson mGson;
        @Inject
        Car mCar;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            DaggerMainActivityComponent.create().inject(this);
            mPerson.eat();
    
            String jsonData = "{'name':'fukq','age':18}";
            Man man = mGson.fromJson(jsonData,Man.class);
            Log.i("fukq","name-------"+man.getName());
    
            String str =mCar.run();
            Log.d("fukq","car---" + str);
        }
    }
    
    error: com.smartisan.dagger2.Engine cannot be provided without an @Provides-annotated method.
    com.smartisan.dagger2.Engine is injected at
    com.smartisan.dagger2.Car.<init>(engine)
    com.smartisan.dagger2.Car is injected at
    com.smartisan.dagger2.MainActivity.mCar
    com.smartisan.dagger2.MainActivity is injected at
    com.smartisan.dagger2.MainActivityComponent.inject(activity)
    

    说明:
    ① 这里报错了,为何呢?因为Engine是抽象的。@Inject无法提供实例。
    ② 这里采用@Module和@Provides来处理。
    3.2.1. 修改GasolineEngline类,去掉@Inject:

    public class GasolineEngline extends Engine {
    
        @Override
        public String work() {
            return "汽油发动机发动";
        }
    }
    

    3.2.2. 创建EngineModule:

    @Module
    public class EngineModule {
    
        @Provides
        public Engine provideEngline(){
            return new GasolineEngline();
        }
    }
    

    3.2.3. 在Component中指定EngineModule:

    @Component(modules = {GsonModule.class,EngineModule.class})
    public interface MainActivityComponent {
        void inject(MainActivity activity);
    }
    

    3.2.4. 在MainActivity 注入Car:

    public class MainActivity extends AppCompatActivity {
        @Inject
        Person mPerson;
        @Inject
        Gson mGson;
        @Inject
        Car mCar;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            DaggerMainActivityComponent.create().inject(this);
            mPerson.eat();
    
            String jsonData = "{'name':'fukq','age':18}";
            Man man = mGson.fromJson(jsonData,Man.class);
            Log.i("fukq","name-------"+man.getName());
    
            String str =mCar.run();
            Log.d("fukq","car---" + str);
        }
    }
    
    11-28 11:23:20.858 19873-19873/? D/fukq: car---汽油发动机发动
    

    4. @Named 和 @Qualifier

    4.1 @Named

    @Qualifier是限定符,@Named是@Qualifier的一种实现。当有两个类都继承同一个父类或者均实现同一个接口。当他们被提供给高层时,Component就不知道到底要提供哪一个依赖对象了。比如上面的汽车(父类),它有一个子类GasolineEngline,我们再提供一个子类DieselEngine给汽车(父类),如下:

    public class DieselEngline extends Engine {
    
        @Override
        public String work() {
            return "柴油发动机发动";
        }
    }
    
    @Module
    public class EngineModule {
    
        @Provides
        public Engine provideGasoline(){
            return new GasolineEngline();
        }
    
        @Provides
        public Engine provideDiesel(){
            return new DieselEngline();
        }
    }
    

    这个时候我们提供了两个Provides,Component不知道选哪个,这个时候@Named就派上了用场,它的作用就是起别名(外号)。

    4.1.1 对EngineModule进行改造:

    @Module
    public class EngineModule {
    
        @Provides
        @Named ("Gasoline")
        public Engine provideGasoline(){
            return new GasolineEngline();
        }
    
        @Provides
        @Named ("Diesel")
        public Engine provideDiesel(){
            return new DieselEngline();
        }
    }
    

    4.1.2 在Car类(父类)指定要采用哪个Provides:

    public class Car {
        private Engine mEngine;
    
        @Inject
        public Car(@Named("Diesel") Engine engine) {
            mEngine = engine;
        }
        public String run(){
            return mEngine.work();
        }
    }
    
    11-28 14:10:18.815 22163-22163/com.smartisan.dagger2 D/fukq: car---柴油发动机发动
    
    4.2 @Qualifier

    @Named 传递的值只能是字符串,而@Qualifier 则更灵活一些,@Qualifier不是直接标记在属性上的,而是用来自定义注解的,如下:

    4.2.1 定义两个不同的注解(自定义注解以后会写一篇博文来讲解)

    @Qualifier
    @Retention(RUNTIME)
    public @interface Gasloline {
    }
    @Qualifier
    @Retention(RUNTIME)
    public @interface Diesel {
    }
    

    说明:只定义两个不同名称的注解即可,空实现即可,因为我们就是通过不同的注解区分Provides,以便让Component找到所要找的实例。记得导包:

    import static java.lang.annotation.RetentionPolicy.RUNTIME;
    

    4.2.2 修改EngineModule类:

    @Module
    public class EngineModule {
    
        @Provides
        @Gasloline
        public Engine provideGasoline(){
            return new GasolineEngline();
        }
    
        @Provides
        @Diesel
        public Engine provideDiesel(){
            return new DieselEngline();
        }
    }
    

    4.2.3 在Car类(父类)指定要采用哪个注解(即用哪个Provides):

    public class Car {
        private Engine mEngine;
    
        @Inject
        public Car(@Gasloline Engine engine) {
            mEngine = engine;
        }
        public String run(){
            return mEngine.work();
        }
    }
    
    11-28 14:36:27.832 22846-22846/com.smartisan.dagger2 D/fukq: car---汽油发动机发动
    

    5. @Singleton和@Scope

    5.1 @Singleton

    @Scope是用来自定义注解的,而@Singleton是用来配合实现局部单例和全局单例的。注意:@Singleton本身不具备创建单例的能力。我们从示例来分析

        @Inject
        Gson mGson;
        @Inject
        Gson mGson2;
    
        Log.d("fukq",mGson.hashCode()+"");
        Log.d("fukq",mGson2.hashCode()+"");
    
        210706522
        73949835
    

    上面是两个Gson的实例,分别是mGson和mGson2,打印了两个实例的内存地址,内存地址不同说明它们不是一个对象,那如果我们想让Gson在MainActivity中是单例,咋弄呢?这个时候@Singleton就派上用场了。

    5.1.1 修改GsonModule,添加@Singleton:

    @Module
    public class GsonModule {
        
        @Singleton
        @Provides
        public Gson provideGson(){
            return new Gson();
        }
    }
    

    5.1.2 在MainActivityComponent中添加@Singleton:

    @Singleton
    @Component(modules = {GsonModule.class,EngineModule.class})
    public interface MainActivityComponent {
        void inject(MainActivity activity);
    }
    

    我们再次打印两个Gson对象的内存地址值,结果如下:

    11-28 15:32:39.425 25927-25927/? D/fukq: 73949835
    11-28 15:32:39.425 25927-25927/? D/fukq: 73949835
    

    说明:这个时候我们发现Gson在MainActivity中是单例,那么我们再创建一个SecondActivity,SecondActivity创建的Gson的内存地址和MainActivity中的是一样的吗?答案是:肯定不一样。因为我们只在MainActivityComponent中添加@Singleton,意思是只在MainActivity中是单例的。那如何实现全局单例呢?我们创建一个全局的Component,也就是说Component保证只有一个实例。如何保证Component只有一个实例呢?我们在Application中初始化即可。

    5.2 @Scope

    我们看下@Singleton的源码:

    @Scope
    @Documented
    @Retention(RUNTIME)
    public @interface Singleton {}
    

    我们发现,它是用@Scope来修饰的。所以这里我们不用@Singleton来实现全局实例,我们用@Scope仿写一个:之所以仿写,一来可以清楚看到@Scope的作用,二来可以自定义注解的名称(总是叫Singleton,很单调)。

    5.2.1 定义@ApplicationScope注解:

    @Scope
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ApplicationScope {
    }
    

    5.2.2 在GsonModule中使用@ApplicationScope:

    @Module
    public class GsonModule {
    
        @ApplicationScope
        @Provides
        public Gson provideGson(){
            return new Gson();
        }
    }
    

    5.2.3 创建ActivityComponent来处理多个Activity:

    @ApplicationScope
    @Component(modules = GsonModule.class)
    public interface ActivityComponent  {
        void inject(MainActivity mainActivity);
        void inject(SecondActivity mainActivity);
    }
    

    5.2.4 创建App类继承Application,用来提供ActivityCompenent实例:

    public class App extends Application {
        
        ActivityComponent mActivityComponent;
    
        @Override
        public void onCreate() {
            super.onCreate();
            mActivityComponent = DaggerActivityComponent.builder().build();
        }
        
        public static App get(Context context){
            return (App) context.getApplicationContext();
        }
        
        ActivityComponent getActivityComponent(){
            return mActivityComponent;
        }
    }
    

    5.2.5 使用全局的Component来注入Gson:

    public class MainActivity extends AppCompatActivity {
        @Inject
        Gson mGson;
        @Inject
        Gson mGson2;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            App.get(MainActivity.this).getActivityComponent().inject(this);
            Log.d("fukq:MainActivity",mGson.hashCode()+"");
            Log.d("fukq:MainActivity",mGson2.hashCode()+"");
            findViewById(R.id.bt_skip_to_second).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    startActivity(new Intent(MainActivity.this,SecondActivity.class));
                }
            });
        }
    }
    
    public class SecondActivity extends AppCompatActivity {
    
        @Inject
        Gson mGson;
        @Inject
        Gson mGson2;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            setContentView(R.layout.activity_main);
    
            App.get(SecondActivity.this).getActivityComponent().inject(this);
            Log.d("fukq:SecondActivity",mGson.hashCode()+"");
            Log.d("fukq:SecondActivity",mGson2.hashCode()+"");
        }
    }
    
    11-28 17:06:28.703 29041-29041/? D/fukq:MainActivity: 150530801
        150530801
    11-28 17:06:44.454 29041-29041/com.smartisan.dagger2 D/fukq:SecondActivity: 150530801
    11-28 17:06:44.454 29041-29041/com.smartisan.dagger2 D/fukq:SecondActivity: 150530801
    

    说明:
    ① 发现MainActivity和SecondActivity中的Gson的内存地址一样,也就是实现了Gson的全局单例。
    ② 利用@Scope可以更好地管理Component和Module之间的匹配关系。比如编译器会检查Component管理的Module,若发现管理的Module中的标注创建实例方法的Scope注解与Component中的Scope注解不一致,就会报错。
    ③ 一般来说会有一个全局的Component,每个界面有自己的Component,当然不是必需,如果页面之间的依赖的类是一样的,可以共用一个Component。

    6. @Component的dependencies

    @Component可以用dependencies依赖于其他Component。这里我们让ActivityComponent依赖SuperComponent。

    6.1 创建类SuperMan:

    public class SuperMan {
        
        @Inject
        public SuperMan() {
        }
        
        public String fighting(){
            return "欲为大树,莫与草争";
        }
    }
    

    6.2 创建SuperModule和SuperComponent:

    @Module
    public class SuperManModule {
    
        @Provides
        public SuperMan provideSuperMan(){
            return new SuperMan();
        }
    }
    
    @Component(modules = SuperManModule.class)
    public interface SuperManComponent {
        SuperMan getSuperMan();
    }
    

    6.3 在ActivityComponent中引入SuperManComponent:

    @ApplicationScope
    @Component(modules = GsonModule.class,dependencies = SuperManComponent.class)
    public interface ActivityComponent  {
        void inject(MainActivity mainActivity);
        void inject(SecondActivity mainActivity);
    }
    

    注意:每次更新Component记得编译下,对应As的小锤子。

    6.4 在此前定义的App类中引入SuperManComponent,修改App代码:

    public class App extends Application {
    
        ActivityComponent mActivityComponent;
    
        @Override
        public void onCreate() {
            super.onCreate();
            mActivityComponent = DaggerActivityComponent.builder().superManComponent(DaggerSuperManComponent.builder().build()).build();
        }
    
        public static App get(Context context){
            return (App) context.getApplicationContext();
        }
    
        ActivityComponent getActivityComponent(){
            return mActivityComponent;
        }
    }
    

    说明:可以对照之前App的代码,不难发现,只是对ActivityComponent的生成进行修改,修改后可以体现出来SuperManComponent和ActivityComponent的依赖关系。

    6.5 在MainActivity中使用SuperMan:

    public class MainActivity extends AppCompatActivity {
        @Inject
        SuperMan mSuperMan;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            App.get(MainActivity.this).getActivityComponent().inject(this);
            String str = mSuperMan.fighting();
            Log.d("fukq", "onCreate: str" + str);
        }
    }
    
    11-29 11:36:27.348 10510-10510/com.smartisan.dagger2 D/fukq: onCreate: str欲为大树,莫与草争
    

    7. 懒加载

    Dagger2 提供了懒加载,就是在注入实例的时候不实例化,而是在使用的时候,调用get方法来 获取实例。修改SuperMan的注入,代码如下:

    public class MainActivity extends AppCompatActivity {
        @Inject
        Lazy<SuperMan> mSuperManLazy;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            App.get(MainActivity.this).getActivityComponent().inject(this);
            SuperMan superMan = mSuperManLazy.get();
            String str = superMan.fighting();
            Log.d("fukq", "onCreate: str" + str);
        }
    }
    
    11-29 11:47:43.576 10925-10925/com.smartisan.dagger2 D/fukq: onCreate: str欲为大树,莫与草争
    

    8. Dagger2 原理分析

    因为Dagger2的应用场景比较多,我们这里进行原理分析,拿Person注入的例子,例子代码我再复制下,省去大家往前面翻:

    public class Person{
        @Inject
        public Person() {
        }
    
        public void eat(){
            Log.i("fukq","我要吃面包");
        }
    }
    
    @Component
    public interface MainActivityComponent {
        void inject(MainActivity mainActivity);
    }
    
    public class MainActivity extends AppCompatActivity {
        @Inject
        Person mPerson;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            DaggerMainActivityComponent.create().inject(this);
            mPerson.eat();
        }
    }
    

    8.1 看下核心代码

    DaggerMainActivityComponent.create().inject(this);
    

    说明:这里是核心代码,我们第一看create方法,第二看inject方法,看清楚两个方法的实现逻辑就能够明白Dagger的核心Component到底做了什么事情,也就能明白Dagger的实现原理。

    public final class DaggerMainActivityComponent implements MainActivityComponent {
      private MembersInjector<MainActivity> mainActivityMembersInjector;
    
      private DaggerMainActivityComponent(Builder builder) {
        assert builder != null;
        initialize(builder); // 4
      }
    
      public static Builder builder() {
        return new Builder(); // 2
      }
    
      public static MainActivityComponent create() {
        return builder().build(); // 1
      }
    
      @SuppressWarnings("unchecked")
      private void initialize(final Builder builder) {
    
        this.mainActivityMembersInjector = MainActivity_MembersInjector.create(Person_Factory.create()); // 5
      }
    
      @Override
      public void inject(MainActivity mainActivity) {
        mainActivityMembersInjector.injectMembers(mainActivity); // 6
      }
    
      public static final class Builder {
        private Builder() {}
    
        public MainActivityComponent build() {
          return new DaggerMainActivityComponent(this); // 3
        }
      }
    }
    

    说明:
    ① Component就是Dagger核心逻辑所在,所以我们看DaggerMainActivityComponent做了什么。
    ② 一步一步看,由表及里:
    先看create()方法,执行的是代码 1 处 :

    public static MainActivityComponent create() {
        return builder().build(); // 1
      }
    

    再看builder()方法:

    public static Builder builder() {
        return new Builder(); // 2
      }
    

    接着看build()方法:

    public MainActivityComponent build() {
          return new DaggerMainActivityComponent(this); // 3
        }
    

    代码3执行的DaggerMainActivityComponent的构造方法,并传入Builder对象:

    private DaggerMainActivityComponent(Builder builder) {
        assert builder != null;
        initialize(builder);  // 4
      }
    

    再接着看initialize()方法,拿到了MembersInjector对象,引用是mainActivityMembersInjector:

    @SuppressWarnings("unchecked")
      private void initialize(final Builder builder) {
    
        this.mainActivityMembersInjector = MainActivity_MembersInjector.create(Person_Factory.create()); // 5
      }  
    

    拿到mainActivityMembersInjector引用后,它干了点啥呢:

      @Override
      public void inject(MainActivity mainActivity) {
        mainActivityMembersInjector.injectMembers(mainActivity); // 6
      }
    

    接着看injectMembers方法:

    public interface MembersInjector<T> {
    
      /**
       * Injects dependencies into the fields and methods of {@code instance}. Ignores the presence or
       * absence of an injectable constructor.
       *
       * <p>Whenever the object graph creates an instance, it performs this injection automatically
       * (after first performing constructor injection), so if you're able to let the object graph
       * create all your objects for you, you'll never need to use this method.
       *
       * @param instance into which members are to be injected
       * @throws NullPointerException if {@code instance} is {@code null}
       */
      void injectMembers(T instance);
    }
    

    发现它是接口MembersInjector的方法,那谁实现了这个接口呢,点左边小原绿色图标:会发现是名为MainActivity_MembersInjector的类,这个名字好熟悉,原来往上退两步,就是代码 5:

      @SuppressWarnings("unchecked")
      private void initialize(final Builder builder) {
    
        this.mainActivityMembersInjector = MainActivity_MembersInjector.create(Person_Factory.create()); // 5
      }
    

    我们又看到了MainActivity_MembersInjector这类,那弄清楚它的类里面的injectMembers和create(Person_Factory.create())方法应该就能分析出来原理了,代码:

    public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
      private final Provider<Person> mPersonProvider;
    
      public MainActivity_MembersInjector(Provider<Person> mPersonProvider) {
        assert mPersonProvider != null;
        this.mPersonProvider = mPersonProvider;  // 2
      }
    
      public static MembersInjector<MainActivity> create(Provider<Person> mPersonProvider) {
        return new MainActivity_MembersInjector(mPersonProvider);  // 1
      }
    
      @Override
      public void injectMembers(MainActivity instance) {
        if (instance == null) {
          throw new NullPointerException("Cannot inject members into a null reference");
        }
        instance.mPerson = mPersonProvider.get();
      }
    
      public static void injectMPerson(MainActivity instance, Provider<Person> mPersonProvider) {
        instance.mPerson = mPersonProvider.get();
      }
    }
    

    因为create方法先于injectMembers方法调用,我们先看create方法:

    public static MembersInjector<MainActivity> create(Provider<Person> mPersonProvider) {
        return new MainActivity_MembersInjector(mPersonProvider);  // 1
      }
    

    会发现调用了MainActivity_MembersInjector类的构造方法:

    public MainActivity_MembersInjector(Provider<Person> mPersonProvider) {
        assert mPersonProvider != null;
        this.mPersonProvider = mPersonProvider;  // 2
      }
    

    这个构造方法传进来的是什么呢?我们往上看

    this.mainActivityMembersInjector = MainActivity_MembersInjector.create(Person_Factory.create());
    

    会发现Person_Factory.create(),那这里做了什么呢?

    public enum Person_Factory implements Factory<Person> {
      INSTANCE;
    
      @Override
      public Person get() {
        return new Person();
      }
    
      public static Factory<Person> create() {
        return INSTANCE;
      }
    }
    

    原来是一个枚举单例 create()方法,返回的是Person_Factory,但是MainActivity_MembersInjector的构造方法的参数是Provider<Person> mPersonProvider,和Person_Factory啥关系呢?怎么就可以直接传入了,看Person_Factory的超类Factory<Person>代码:

    public interface Factory<T> extends Provider<T> {
    }
    

    原来Factory<Person>的超类是Provider<T>,怪不得可以直接传入呢。那现在我们看看传进来的这个参数Provider<Person> mPersonProvider 干了点啥呢:

    @Override
      public void injectMembers(MainActivity instance) {
        if (instance == null) {
          throw new NullPointerException("Cannot inject members into a null reference");
        }
        instance.mPerson = mPersonProvider.get();
      }
    

    原来是在injectMembers方法中,这样正好不用额外去分析injectMembers方法了,instance是MainActivity的引用, instance.mPerson就是它的成员变量Person对象的引用mPerson,那有了引用了,等号右边是什么呢?

    public enum Person_Factory implements Factory<Person> {
      INSTANCE;
    
      @Override
      public Person get() {
        return new Person();
      }
    
      public static Factory<Person> create() {
        return INSTANCE;
      }
    }
    

    往上看:看到了get方法的返回是

    return new Person();
    

    看到这里,我们发现讲了这么多,这3个辅助类的作用就是调用inject方法的时候,将新创建的Person实例赋值给MainActivity的成员变量Person。其中Person_Factory用来生产Person的实例,MainActivity_MembersInjector用来把Person的实例赋值给MainActivity的成员变量Person,而DaggerMainActivityComponent就是为了把两者给串联起来。而这就是Dagger的实现原理。
    这里我们还看出了,单一职责原则和建造者设计模式的引用,建议平时多看看源码,会让我们受益匪浅。一起加油!

    9. 后续

    如果大家喜欢这篇文章,欢迎点赞;如果想看更多 Dagger 方面的技术,欢迎关注!

    相关文章

      网友评论

      本文标题:看完不懂Dagger2我跪搓板

      本文链接:https://www.haomeiwen.com/subject/blmgqqtx.html