Android |《看完不忘系列》之dagger
{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"嗨,我是哈利迪~《看完不忘系列》将以"},{"type":"codeinline","content":[{"type":"text","text":"从树干到细枝"}]},{"type":"text","text":"的思路分析一些技术框架,本文将对开源项目"},{"type":"codeinline","content":[{"type":"text","text":"dagger"}]},{"type":"text","text":"进行介绍。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文约3800字,阅读大约10分钟。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Dagger源码基于最新版本2.28.3"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/33/33c3322789466e3b3b6cab1534668570.jpeg","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"背景"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"依赖注入(Dependency Injection,DI)遵循控制反转(Inversion of Control,IoC)原则,简单来说就是"},{"type":"codeinline","content":[{"type":"text","text":"创建对象时给对象传入依赖"}]},{"type":"text","text":",通过传入不同实例来实现不同行为(控制),比如常见的构造方法和setter都叫注入。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"简单概括一下谷歌的"},{"type":"link","attrs":{"href":"https://developer.android.google.cn/training/dependency-injection","title":""},"content":[{"type":"text","text":"造车栗子"}]},{"type":"text","text":","}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一、不注入,由Car类自己创建依赖的Engine实例,当需要替换汽车引擎时,需要修改Car类,违背了开放封闭原则,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"class Car {\n private Engine engine = new Engine();\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"二、手动依赖注入,如构造方法和setter,当需要替换汽车引擎时,传入不同的引擎实现(如ElectricEngine extends Engine)即可,无需修改Car类,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"//1.构造方法注入\nclass Car {\n private final Engine engine;\n \n public Car(Engine engine) {\n this.engine = engine;\n }\n}\n\n//2.setter注入\nclass Car {\n private Engine engine;\n\n public void setEngine(Engine engine) {\n this.engine = engine;\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"三、随着汽车配件变多,依赖注入的代码也会越来越多,如汽车需要引擎、轮胎,引擎又需要气缸和火花塞,这样一层层下去注入代码成指数级上升,出现了大量创建对象的样板代码,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/d3/d3005822e48f49ba95657437e170cb5b.jpeg","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"class Car {\n private final Engine engine;//引擎\n private final Wheel wheel;//轮胎\n\n public Car(Engine engine,Wheel wheel) {\n this.engine = engine;\n this.wheel = wheel;\n }\n}\n\nclass Engine {\n private final Cylinder cylinder;//气缸\n private final SparkPlug sparkPlug;//火花塞\n\n public Car(Cylinder cylinder,SparkPlug sparkPlug) {\n this.cylinder = cylinder;\n this.sparkPlug = sparkPlug;\n }\n}\n\nvoid main(){\n //为了造辆车,要new出一堆对象,还要构造方法注入,套娃既视感\n Cylinder cylinder = new Cylinder();\n SparkPlug sparkPlug = new SparkPlug();\n Engine engine = new Engine(cylinder,sparkPlug);\n Wheel wheel = new Wheel();\n Car car = new Car(engine,wheel);\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"从代码可以看出有两大痛点,一是要创建"},{"type":"codeinline","content":[{"type":"text","text":"很多对象"}]},{"type":"text","text":",二是对象的创建过程还需"},{"type":"codeinline","content":[{"type":"text","text":"有序"}]},{"type":"text","text":",即要先有气缸和火花塞才能造引擎,先有引擎和轮胎才能造车,这样使用方还需"},{"type":"codeinline","content":[{"type":"text","text":"花时间了解配件间的依赖关系"}]},{"type":"text","text":",很是不便。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"于是就有了一些库来实现自动依赖注入,有两个实现思路(koin的实现以后再聊~),"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"一是运行期反射连接依赖项,编译影响小,但运行慢"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"二是编译期就连接依赖项,创建辅助类需要额外的io和编译耗时,会拖慢编译速度,但运行快"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"像Android内存和算力都有限的终端设备,dagger当然是选择思路2啦。dagger通过"},{"type":"codeinline","content":[{"type":"text","text":"注解"}]},{"type":"text","text":"标记"},{"type":"codeinline","content":[{"type":"text","text":"对象创建姿势"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"依赖关系"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"作用域"}]},{"type":"text","text":"等信息,在编译期创建辅助类,从而实现自动依赖注入。不过dagger的上手成本略高,谷歌后来又推出了Hilt,旨在让我们用得"},{"type":"text","marks":[{"type":"del"}],"text":"舒心"},{"type":"text","text":","}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://developer.android.google.cn/training/dependency-injection/hilt-android","title":""},"content":[{"type":"text","text":"Hilt"}]},{"type":"text","text":" 是推荐用于在 Android 中实现依赖项注入的 Jetpack 库。Hilt 通过为项目中的每个 Android 类提供容器并自动为您管理其生命周期,定义了一种在应用中执行 DI 的标准方法。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":">"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Hilt 在热门 DI 库 "},{"type":"link","attrs":{"href":"https://developer.android.google.cn/training/dependency-injection/dagger-basics","title":""},"content":[{"type":"text","text":"Dagger"}]},{"type":"text","text":" 的基础上构建而成,因而能够受益于 Dagger 提供的编译时正确性、运行时性能、可伸缩性和 Android Studio 支持。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":">"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"-- 谷歌"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Hilt就先放一放,下面我们先开始dagger之旅吧~"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"补:关于手动注入的痛点,可以看下谷歌的"},{"type":"link","attrs":{"href":"https://developer.android.google.cn/training/dependency-injection/manual","title":""},"content":[{"type":"text","text":"手动依赖项注入"}]},{"type":"text","text":"(看完或许能更好的理解dagger的设计)。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"树干"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"简单使用"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"依赖,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"groovy"},"content":[{"type":"text","text":"implementation 'com.google.dagger:dagger:2.28.3'\nannotationProcessor 'com.google.dagger:dagger-compiler:2.28.3'"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"@Inject和@Component"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"@Inject标记实例的创建姿势,汽车和引擎类,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"class Car {\n private final Engine mEngine;\n\n @Inject //告诉dagger如何创建Car\n public Car(Engine engine) {\n mEngine = engine;\n }\n\n public void start() {\n mEngine.start();\n }\n}\n\nclass Engine {\n @Inject //告诉dagger如何创建Engine\n public Engine() {\n }\n\n public void start() {\n Log.e(\"哈利迪\", \"引擎发动,前往秋名山\");\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这样dagger就能生成类似 new Car(new Engine()) 的代码来创建实例,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"@Component标记所要创建的实例有哪些,如在造车图纸(接口)里声明要造车,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Component //告诉dagger要造啥\ninterface CarGraph {\n //造车\n Car makeCar();\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"make一下项目,生成Car"},{"type":"text","marks":[{"type":"italic"}],"text":"Factory、Engine"},{"type":"text","text":"Factory和DaggerCarGraph三个类,在Activity中使用,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"class DaggerActivity extends AppCompatActivity {\n\n @Override\n protected void onCreate(Bundle savedInstanceState) {\n super.onCreate(savedInstanceState);\n setContentView(R.layout.activity_dagger);\n //得到造车图纸\n CarGraph carGraph = DaggerCarGraph.create();\n //造出一辆汽车\n Car car = carGraph.makeCar();\n //引擎发动\n car.start();\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"注入姿势二,还可以直接把汽车注入给Activity,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Component //告诉dagger要造啥\npublic interface CarGraph {\n //造车\n Car makeCar();\n\n //新增:告诉dagger有个Activity要注入\n void inject(DaggerActivity activity);\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"make一下,这时会多出一个类DaggerActivity_MembersInjector(成员注入器),我们后面再看,在Activity中,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"class DaggerActivity extends AppCompatActivity {\n //向Activity注入汽车\n @Inject\n Car mCar;\n\n @Override\n protected void onCreate(Bundle savedInstanceState) {\n super.onCreate(savedInstanceState);\n setContentView(R.layout.activity_dagger);\n //得到造车图纸\n CarGraph carGraph = DaggerCarGraph.create();\n //告诉dagger有个Activity要注入\n carGraph.inject(this);\n //此时,mCar已被dagger自动赋值,我们可以直接发动引擎\n mCar.start();\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不管是哪种姿势,都可以看出,Activity只管提车,无需关心造车内部的细节(用了什么引擎),这样以后要换引擎了,Activity和Car也不用改动代码。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"@Module和@Binds"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那么问题来了,通常我们都是面向接口编程,现在想把Engine换成IEngine接口咋整呢?因为我有两种引擎,分别是汽油车的GasEngine,和电动车的ElectricEngine,接口没有构造方法怎么注入?此时@Module和@Binds注解就派上用场了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"定义引擎接口和实现类,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"interface IEngine {\n public void start();\n}\n\nclass GasEngine implements IEngine {//汽油引擎\n @Inject\n public GasEngine() {\n }\n\n @Override\n public void start() {\n Log.e(\"哈利迪\", \"汽油 引擎发动,前往秋名山\");\n }\n}\n\nclass ElectricEngine implements IEngine {//电动引擎\n @Inject\n public ElectricEngine() {\n }\n\n @Override\n public void start() {\n Log.e(\"哈利迪\", \"电动 引擎发动,前往秋名山\");\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然后Car我们不要了,新写一个汽车类NewCar,让他依赖于接口IEngine而非类,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"class NewCar {\n //依赖于接口\n private final IEngine mEngine;\n\n @Inject //告诉dagger如何创建NewCar\n public NewCar(IEngine engine) {\n mEngine = engine;\n }\n\n public void start() {\n mEngine.start();\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面有请@Module和@Binds登场!建一个抽象类GasEngineModule,表示汽油引擎模块,用于提供汽油引擎,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Module\nabstract class GasEngineModule {//汽油引擎模块\n @Binds\n abstract IEngine makeGasEngine(GasEngine engine);\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然后在造车图纸CarGraph里支持一下NewCar的创建,把Module引入Component,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Component(modules = {GasEngineModule.class})\n//引入汽油引擎模块\npublic interface CarGraph {\n //...\n\n //造新车\n NewCar makeNewCar();\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Activity使用,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"//DaggerActivity.java\nvoid onCreate(Bundle savedInstanceState) {\n CarGraph carGraph = DaggerCarGraph.create();\n NewCar newCar = carGraph.makeNewCar();\n newCar.start();\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"搞定~"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/62/6252b49d409487b4327bfaede65ea35c.jpeg","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这时如果想要把NewCar换成电动引擎,直接依赖新的模块即可,新增模块ElectricEngineModule,用于提供电动引擎,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Module\npublic abstract class ElectricEngineModule {//电动引擎模块\n @Binds\n abstract IEngine makeElectricEngine(ElectricEngine engine);\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"GasEngineModule模块换成ElectricEngineModule,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Component(modules = {ElectricEngineModule.class})//替换\npublic interface CarGraph {\n //...\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"运行就能得到电动车了,可见这个过程我们不需要修改NewCar就能换掉引擎(偷梁换柱)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"@IntoMap和@StringKey"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"又有一天,突然想开双混动汽车了咋整,就是说汽油引擎和电动引擎我全都要,我们发现@Component的modules可以传入数组,那试试把两个引擎模块都传进去,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Component(modules = {GasEngineModule.class, ElectricEngineModule.class})\npublic interface CarGraph {\n //...\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"make一下,不用想也知道会出错,NewCar只有一个依赖IEngine接口,这时dagger已经不知道,造NewCar到底要传入哪个引擎了,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/10/10f1c6f55b2463f88243419cb9a2f4c1.jpeg","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那怎么办?支持多绑定的@IntoMap和@StringKey登场了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"IntoMap表示会把这个Module存进map里,StringKey表示Module名字,这个名字也会作为map的key,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Module\nabstract class GasEngineModule {//汽油引擎模块\n @Binds\n @IntoMap\n @StringKey(\"Gas\")\n abstract IEngine makeGasEngine(GasEngine engine);\n}\n\n@Module\nabstract class ElectricEngineModule {//电动引擎模块\n @Binds\n @IntoMap\n @StringKey(\"Electric\")\n abstract IEngine makeElectricEngine(ElectricEngine engine);\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然后修改一下NewCar,此时不再只是依赖一个引擎接口IEngine了,而是一组引擎,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"class NewCar {\n //我现在是混动车了,要用map接收引擎\n private final Map mEngineMap;\n\n @Inject //告诉dagger如何创建NewCar\n public NewCar(Map engineMap) {\n mEngineMap = engineMap;\n }\n\n public void start() {\n //双混动走起~\n for (Map.Entry entry : mEngineMap.entrySet()) {\n entry.getValue().start();\n //汽油 引擎发动,前往秋名山\n //电动 引擎发动,前往秋名山\n }\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Activity代码不用改动,双混动车就造好了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/45/45e803043ee0f97aed7e25e146e15797.jpeg","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"@Singleton"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果想要给双混动NewCar限量全球一款,可以用@Singleton指定为单例,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Singleton //单例,我现在是限量款混动车\npublic class NewCar {\n //...\n}\n\n@Singleton //造车图纸也需跟着单例\n@Component(modules = {GasEngineModule.class, ElectricEngineModule.class})\npublic interface CarGraph {\n //...\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Activity运行,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"//DaggerActivity.java\nvoid onCreate(Bundle savedInstanceState) {\n CarGraph carGraph = DaggerCarGraph.create();\n NewCar newCar = carGraph.makeNewCar();\n newCar.start();\n NewCar newCar2 = carGraph.makeNewCar();\n newCar2.start();\n //newCar和newCar2是同一个实例\n Log.e(\"哈利迪\", newCar.hashCode() + \",\" + newCar2.hashCode());\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"dagger的使用就先聊到这啦,相信对dagger也已经有了初步认识,还有些注解没讲到,比如:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"@Provides:当我们没法用@Inject来标记实例的创建姿势时,可以用@Module和@Provides来提供实例,比如Retrofit是三方库的类我们没法标记其构造方法,则可以用Provides提供,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Module\npublic class NetworkModule {\n @Provides\n public Retrofit provideRetrofit() {\n return new Retrofit.Builder()\n .baseUrl(\"xxx\")\n .build();\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"@Scope:作用域 ..."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"@Subcomponent:子组件..."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"注解还有很多,准备放到细枝篇来写了...🤣"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"实现原理"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"dagger编译期解析注解创建辅助类的过程就不分析了,我们直接看他生成的辅助类,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/aa/aae56f0390d747ac983e86712b32fb0f.jpeg","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"注:一开始写接口名字时,用造车图纸CarGraph而不是造车厂CarFactory,是为了避免和dagger的生成类搞混,用CarGraph有几何图的寓意,可以理解成造车蓝图(PPT),让我们一起,为梦想窒息..."}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们看到DaggerCarGraph,他实现了我们的CarGraph接口,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"class DaggerCarGraph implements CarGraph {\n //Provider,提供多引擎map,\n private Provider
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.