当前位置: 首页 > news >正文

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

定义 ApplicationComponent

@Component(modules = {AndroidInjectionModule.class,BaseActivityModule.class
})
public interface ApplicationComponent {void inject(APP app);
}

定义 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();
}

创建提供 Object 的 Module

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

@Module
public class HomeActivityModule {@Providesstatic DatabaseObject provideDatabaseObject(HomeActivity homeActivity) {return new DatabaseObject(homeActivity);}
}
@Module
public class SplashActivityModule {@Providesstatic DatabaseObject provideDatabaseObject(SplashActivity splashActivity) {return new DatabaseObject(splashActivity);}
}

通过 ApplicationComponent 向 Application 注入 AndroidInjector

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

public class APP extends Application {public static APP application;ApplicationComponent applicationComponent;@InjectDispatchingAndroidInjector<Object> androidInjector;@Overridepublic 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;}
}

通过 AndroidInjector 向 Activity 统一注入对象

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

public class BaseActivity extends AppCompatActivity {@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);AndroidInjector androidInjector = APP.application.androidInjector();androidInjector.inject(this);}
}

效果测试

@SuppressWarnings("all")
public class HomeActivity extends BaseActivity {ActivityHomeBinding binding;@InjectDatabaseObject databaseObject;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);binding = ActivityHomeBinding.inflate(getLayoutInflater());setContentView(binding.getRoot());test();}@Functionprotected void test() {System.err.println(databaseObject.hashCode());}@Overridepublic void onBackPressed() {finish();startActivity(new Intent(this, HomeActivity.class));}
}

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

只要我们在 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

相关文章:

  • HarmonyOS开发(二):TypeScript入门
  • 移动端APP版本治理
  • C复习-预处理器:define+条件编译+文件包含
  • Redis05-集群方案
  • 新版软考高项试题分析精选(三)
  • SoftwareTest6 - 用 Selenium 怎么点点点
  • Alter database open fails with ORA-00600 kcratr_nab_less_than_odr
  • CSS BFC是什么,应用实例
  • 阿里云国际站:云备份
  • 【MybatisPlus】条件构造器、自定义SQL、Service接口
  • Java排序算法之基数排序
  • 物联网AI MicroPython学习之语法 network网络配置模块
  • 2010年数据结构408
  • Realistic fault detection of li-ion battery via dynamical deep learning
  • JimuReport积木报表 v1.6.5 版本发布—免费报表工具
  • 【跃迁之路】【735天】程序员高效学习方法论探索系列(实验阶段492-2019.2.25)...
  • Android框架之Volley
  • Apache的80端口被占用以及访问时报错403
  • canvas 绘制双线技巧
  • create-react-app项目添加less配置
  • js中forEach回调同异步问题
  • Mocha测试初探
  • MySQL QA
  • PHP的类修饰符与访问修饰符
  • Python 使用 Tornado 框架实现 WebHook 自动部署 Git 项目
  • seaborn 安装成功 + ImportError: DLL load failed: 找不到指定的模块 问题解决
  • SSH 免密登录
  • Work@Alibaba 阿里巴巴的企业应用构建之路
  • 干货 | 以太坊Mist负责人教你建立无服务器应用
  • 七牛云假注销小指南
  • 前端 CSS : 5# 纯 CSS 实现24小时超市
  • 十年未变!安全,谁之责?(下)
  • 体验javascript之美-第五课 匿名函数自执行和闭包是一回事儿吗?
  • 微服务框架lagom
  • 学习笔记DL002:AI、机器学习、表示学习、深度学习,第一次大衰退
  • 用简单代码看卷积组块发展
  • 优化 Vue 项目编译文件大小
  • 深度学习之轻量级神经网络在TWS蓝牙音频处理器上的部署
  • elasticsearch-head插件安装
  • postgresql行列转换函数
  • ​无人机石油管道巡检方案新亮点:灵活准确又高效
  • $分析了六十多年间100万字的政府工作报告,我看到了这样的变迁
  • (09)Hive——CTE 公共表达式
  • (4)(4.6) Triducer
  • (附源码)springboot 校园学生兼职系统 毕业设计 742122
  • (论文阅读30/100)Convolutional Pose Machines
  • (实战篇)如何缓存数据
  • (五)IO流之ByteArrayInput/OutputStream
  • (转)3D模板阴影原理
  • (转)创业的注意事项
  • (轉貼) 蒼井そら挑戰筋肉擂台 (Misc)
  • (自适应手机端)响应式新闻博客知识类pbootcms网站模板 自媒体运营博客网站源码下载
  • ***测试-HTTP方法
  • .NET Core 通过 Ef Core 操作 Mysql
  • .NET MVC、 WebAPI、 WebService【ws】、NVVM、WCF、Remoting