• 【Android】Dagger2 通过 AndroidInjector 简化模版代码


    前面我们已经详细讲解过,如何通过 Component 和 Module 向 Activity 注入对象

    这是基本的使用方法,它的缺点是当 Activity 特别多时,就需要非常多的 Component 和 Module 类

    现在我们来讲解,如何通过 AndroidInjector 向基类进行统一注入

    AndroidInjector 使用方法

    定义 DatabaseObject,可用依赖于不同对象,在不同 Activity 中有不同作用

    public class DatabaseObject {
    
        HomeActivity homeActivity;
    
        SplashActivity splashActivity;
    
        public DatabaseObject() {
    
        }
    
        public DatabaseObject(HomeActivity homeActivity) {
            this.homeActivity = homeActivity;
        }
    
        public DatabaseObject(SplashActivity splashActivity) {
            this.splashActivity = splashActivity;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    定义 ApplicationComponent

    @Component(modules = {
            AndroidInjectionModule.class,
            BaseActivityModule.class
    })
    public interface ApplicationComponent {
    
        void inject(APP app);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    定义 ApplicationComponent 的子组件

    注意,这里的 Module 不同于常规的 Module,它并不用来提供对象,而是用来提供子组件的

    Dagger 会根据每个@Contributes方法创建一个对应的SubComponent

    @Module
    public abstract class BaseActivityModule {
    
        @ContributesAndroidInjector(modules = HomeActivityModule.class)
        abstract HomeActivity contributesHomeActivity();
    
        @ContributesAndroidInjector(modules = SplashActivityModule.class)
        abstract SplashActivity contributesSplashActivity();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    创建提供 Object 的 Module

    DatabaseObject 依赖于 Activity,每个 Activity 的 Object 都是一个单独的实例,这种情景可用通过静态方法去创建

    @Module
    public class HomeActivityModule {
    
        @Provides
        static DatabaseObject provideDatabaseObject(HomeActivity homeActivity) {
            return new DatabaseObject(homeActivity);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    @Module
    public class SplashActivityModule {
    
        @Provides
        static DatabaseObject provideDatabaseObject(SplashActivity splashActivity) {
            return new DatabaseObject(splashActivity);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    通过 ApplicationComponent 向 Application 注入 AndroidInjector

    AndroidInjector 能够访问所有的 Component 和 Module,这样它就能自动帮助我们向 Activity 注入对象了

    public class APP extends Application {
    
        public static APP application;
    
        ApplicationComponent applicationComponent;
    
        @Inject
        DispatchingAndroidInjector<Object> androidInjector;
    
        @Override
        public void onCreate() {
            super.onCreate();
            application = this;
            applicationComponent = DaggerApplicationComponent.create();
            applicationComponent.inject(this);
        }
    
        public static ApplicationComponent applicationComponent() {
            return application.applicationComponent;
        }
    
        public static AndroidInjector<Object> androidInjector() {
            return application.androidInjector;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    通过 AndroidInjector 向 Activity 统一注入对象

    AndroidInjector 会根据之类 Activity 的真实类名,来找到对应的 Component 和 Module,然后帮我们自动注入对象

    public class BaseActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            AndroidInjector androidInjector = APP.application.androidInjector();
            androidInjector.inject(this);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    效果测试

    @SuppressWarnings("all")
    public class HomeActivity extends BaseActivity {
    
        ActivityHomeBinding binding;
    
        @Inject
        DatabaseObject databaseObject;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            binding = ActivityHomeBinding.inflate(getLayoutInflater());
            setContentView(binding.getRoot());
            test();
        }
    
        @Function
        protected void test() {
            System.err.println(databaseObject.hashCode());
        }
    
        @Override
        public void onBackPressed() {
            finish();
            startActivity(new Intent(this, HomeActivity.class));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    通过打印结果可以看到,对象确实注入成功了

    只要我们在 BaseActivity 写一行注入代码,就可用为所有 Activity 自动注入对象

    Dagger 原理分析

    上面已经给出使用方法,下面我们再逐步讲解代码作用,以及 Dagger 是如何生成代码的

    这里我没有给出完整的源码,而是将代码的核心流程概述出来

    因为 Dagger 的代码量特别大,但是流程本身其实很简单,给出大量模版代码反而会影响大家去理解核心流程

    通过 BaseActivityModule 简化代码

    • ApplicationComponent依赖BaseActivityModule

    • BaseActivityModule中的每个@Contribute方法,都会对应生成一个SubActivityComponent

    • BaseActivityModule中的每个@Contribute方法,都会对应生成一个SubActivityComponentFactory

    • BaseActivityModuleAndroidInjector之所以能简化代码,是因为 Dagger 根据@Contribute方法自动帮我们生成了SubActivityComponent

    • 实际上,这里的BaseActivityModule只是用来标记要生成哪些SubActivityComponent的,在源码中根本就没有用到它

    • 如果我们需要向BaseActivity中统一注入其它对象,可以自己单独再创建一个 Module

    AndroidInjector 和 ApplicationComponent 之间的关系

    整体的思路我们已经清楚了,是 Dagger 帮我们省略了许多的模版代码工作,现在我们开始理一下细节上是如何实现的

    我们是统一通过 AndroidInjector 去注入的,实现的关键在于 AndroidInjector 如何提供 Activity

    • 所有工作都是从ApplicationComponent开始的,而且它是单例的,所以任何对象都能拿到它的引用

    • ApplicationComponent依赖AndroidInjectionModule,这个 Dagger 内置 Module 可以帮我们注入AndroidInjector对象

    • ApplicationComponent在向 Application 注入AndroidInjector时,同时会将自己所有的SubComponentFactoryProvider全部传给AndroidInjector

    • 因此AndroidInjector实际是通过ApplicationComponent::SubComponentFactoryProvider来提供 Activity 的

    • SubComponentFactoryProvider做的工作很简单,直接 new 一个SubComponentFactory

    • AndroidInjector向 Activity 注入对象时,实际是根据Activity::className找到对应的Provider,通过Provider创建Factory,通过Factory创建SubComponent,将当前 Activity 实例传给SubComponent,剩下的注入工作交给SubComponent就好了

    • 以上是通过ApplicationComponent拿到SubComponent的过程,SubComponent拿到Object的流程大体相似,主要是通过Provider+Factory

    SubComponent 如何注入 Object

    • AndroidInjector定义了一个 inject 方法,负责向AndroidTarget注入对象

    • AndroidInjector.Factory 定义了一个 create 方法,负责根据AndroidTarget创建 AndroidInjector

    • AndroidInjector 分为两种,一种是专门为绑定的AndroidTarget注入对象,一种是 DispatchingAndroidInjector,自身不负责注入对象,而是将注入工作分发给 SubAndroidInjector去处理

    • ApplicationComponent 内部包含了多个SubComponent.Factory,它们继承自 AndroidInjector.Factory接口,用于创建SubComponent

    • SubComponent实现了AndroidInjector接口,用于向绑定的 Activity 注入对象

    • SubComponent就是SubAndroidInjector,所以上一节中,Application::AndroidInjector的实际是在管理SubAndroidInjector

    • SubComponent内部持有了 ModuleActivity,然后将这两个对象交给 ObjectFactory

    • ObjectFactory 会生成一个静态方法,该方法接受 ModuleActivity 两个参数,然后调用 Module::staticProvide 方法来创建 Object

  • 相关阅读:
    Codeforces Round #529 (Div. 3) F. Make It Connected(最小生成树)
    表单标签。。
    第10章——系统级I/O
    Vue2.0开发之——Vue组件-组件的基本使用(31)
    SQLite 学习笔记2 - 常用命令和示例
    异构数据源同步之数据同步 → DataX 使用细节
    Redis的集群模式搭建
    这款开源神器,让聚类算法从此变得简单易用
    Android versionCode会变成指定数值加001、002、003等后缀
    springboot的Home F家居系统的设计与管理
  • 原文地址:https://blog.csdn.net/u013718730/article/details/134413446