dagger的用途就是:讓你不需要初始化對(duì)象苹粟。換句話說(shuō)肿嘲,任何對(duì)象聲明完了就能直接用滑燃。
依賴注入的好處
重用 Car,依賴通過(guò)外部傳入過(guò)來(lái)疆液!
`* 重用類以及分離依賴項(xiàng):更容易換掉依賴項(xiàng)的實(shí)現(xiàn)一铅。由于控制反轉(zhuǎn),代碼重用得以改進(jìn)堕油,并且類不再控制其依賴項(xiàng)的創(chuàng)建方式馅闽,而是支持任何配置飘蚯。
- 易于重構(gòu):依賴項(xiàng)成為 API Surface 的可驗(yàn)證部分,因此可以在創(chuàng)建對(duì)象時(shí)或編譯時(shí)進(jìn)行檢查福也,而不是作為實(shí)現(xiàn)詳情隱藏局骤。`
目的,改造演變:
第一種:直接new 暴凑,很多個(gè)地方new
第二種:統(tǒng)一new 峦甩,通過(guò)工廠的方式new,以后只改一個(gè)地方就可以
第三種:統(tǒng)一的地方现喳,自動(dòng)new
如何解藕凯傲?
1.MVP + Dagger2
專為MVP模式中的P層和V層做進(jìn)一步解耦
因?yàn)樵贛VP模式中Activity持有presenter的引用,同時(shí)presenter也持有view的引用嗦篱,這樣便于更新UI界面冰单,這樣Activity就和 presenter僅僅的耦合在一起了,而Dagger2是依賴注入框架就是解耦合的灸促,所以子MVP中使用Dagger2也就再好不過(guò)了诫欠。
activity持有了presenter的引用并且創(chuàng)建了該對(duì)象,但是如果presenter的構(gòu)造函數(shù)發(fā)生改變則這里也需要改變浴栽,其實(shí)所有和presenter構(gòu)造函數(shù)相關(guān)的代碼都要改變荒叼。
把很多對(duì)象new的地方統(tǒng)一起來(lái)了。之前用的是工廠模式的方式典鸡!工廠比直接new好一點(diǎn)
,dagger2是自動(dòng)注冊(cè)被廓,自動(dòng)手寫了很多new
我的理解:
1).MVP中 present還是會(huì)有view的依賴!
如果很多個(gè)地方使用這個(gè)presenter萝玷。只要改一個(gè)地方就可以了嫁乘,不用改多個(gè)地方。
2). 另外一種情況:
A里面有B球碉, B里面有c亦渗,C里面有D。
如果都手動(dòng)new 汁尺,如果后面改起來(lái)法精,就會(huì)很麻煩!
2.dagger2+組件化
一:Dagger2是什么痴突?
是一個(gè)依賴注入框架搂蜓,butterknife也是一個(gè)依賴注入框架。不過(guò)butterknife辽装,最多叫奶油刀帮碰,Dagger2被叫做利器啊,他的主要作用拾积,就是對(duì)象的管理
優(yōu)點(diǎn):
其目的是為了降低程序耦合殉挽。
隨即而來(lái)的就是可測(cè)試性丰涉,可維護(hù),可擴(kuò)展性就大大提高了
很多小白對(duì)于Dagger2是啥渾然不知斯碌,更不知其能帶來(lái)的好處了一死。
這里舉個(gè)例子,比如有個(gè)類A傻唾,他的構(gòu)造函數(shù)需要傳入B,C投慈;然后代碼里有10個(gè)地方實(shí)例化了A,那如果功能更改冠骄,A的構(gòu)造函數(shù)改成了只有B伪煤,這個(gè)時(shí)候,你是不是要去這10個(gè)地方一個(gè)一個(gè)的改凛辣?如果是100個(gè)地方抱既,你是不是要吐血?扁誓!如果采用dagger2防泵,這樣的需求只需要改1-2個(gè)地方,你感覺(jué)怎么樣跋理?對(duì)你有誘惑嗎?
原理:
這類依賴注入框架都已經(jīng)采用了apt代碼自動(dòng)生成技術(shù)恬总,其注解是停留在編譯時(shí)前普,完全不影響性能。
dagger是使用依賴注入的方式壹堰,使用Annotation給需要注入的對(duì)象做標(biāo)記拭卿,通過(guò)inject()方法自動(dòng)注入所有對(duì)象,從而完成自動(dòng)的初始化
dagger2 解決什么問(wèn)題
第一:dagger 是一個(gè)依賴注入框架贱纠,首要任務(wù)當(dāng)然是解決依賴注入的問(wèn)題峻厚。
第二:dagger主要想通過(guò)編譯時(shí)產(chǎn)生代碼的方式來(lái)解決那些基于反射的依賴注入框架所存在的缺點(diǎn),例如性能問(wèn)題谆焊,開(kāi)發(fā)過(guò)程中存在的問(wèn)題惠桃。
注入的形式:
<pre style="margin: 8px 0px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; background-color: rgb(43, 43, 43); color: rgb(169, 183, 198); font-family: 宋體; font-size: 0.8rem;">public class MainActivity extends AppCompatActivity {
@Named("dev")
@Inject
MainApi apiDev; @Named("release")
@Inject
MainApi apiRelease; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); DaggerMainComponent.builder()
.mainModule(new MainModule(this))
.mainChildModule(new MainChildModule())
.build()
.inject(this);
apiDev.eat();
apiRelease.eat();
Log.i("TAG","apiDev--->" + apiDev);
Log.i("TAG","apiRelease--->" + apiRelease);
}</pre>
3要素:Inject Component Module
@Inject
在A類中標(biāo)記B類的字段:告訴dagger 我們要注入B類的實(shí)例到A類中,你幫我搞定辖试。
在B類中標(biāo)記B類的構(gòu)造函數(shù):告訴dagger B類是一個(gè)可以被注入的類辜王,如果你想把B的實(shí)例對(duì)象注入到其他類中,例如注入到A類中罐孝,是沒(méi)有任何問(wèn)題的呐馆。
@Component :中間橋接,對(duì)外接口
一般是一個(gè)使用 @Component標(biāo)記的接口莲兢,其持有A類的實(shí)例汹来,其在A類中發(fā)現(xiàn)有使用@Inject
標(biāo)記的屬性b
@Module和 providers綁定在一起
C類是一個(gè)沒(méi)有使用@Inject
注解其構(gòu)造函數(shù)的類
@Module注解表示续膳,這個(gè)類是一個(gè)Module,Module的作用是提供信息收班,讓ObjectGraph知道應(yīng)該怎樣注入所有的依賴
3坟岔、Component依賴Component
1、最簡(jiǎn)單不帶Module的Inject方式
由我們自己定義的類闺阱,我們可以自由修改的情況下我們使用這種方式炮车,也分為兩種:帶參數(shù)和不帶參數(shù)的。
a酣溃、構(gòu)造參數(shù)不帶參數(shù)的:
例子:
b瘦穆、構(gòu)造參數(shù)帶參數(shù)的:
構(gòu)造函數(shù)如果帶了inject注入的話,類就默認(rèn)被注入了赊豌,不用像無(wú)慘的一樣
例子:
發(fā)現(xiàn)Factory的構(gòu)造函數(shù)被@Inject標(biāo)注了且?guī)в幸粋€(gè)參數(shù)扛或,
然后dagger2就去尋找Product發(fā)現(xiàn)它的構(gòu)造函數(shù)也被@Inject標(biāo)注并且無(wú)參數(shù),于是dagger2把Product的實(shí)例注入給FactoryActivity
2碘饼、帶Module的Inject方式
應(yīng)用場(chǎng)景:若是我們引入的第三方庫(kù)不能隨意改動(dòng)代碼的話就不方便了熙兔,我們這里使用如下RetrofitManager模擬不可改動(dòng)代碼的情況:
- 第三方庫(kù)提供的類,它們的構(gòu)造方法不能被注解
對(duì)于這樣的情況艾恼,可以使用@Provides注解來(lái)提供專用的初始化方法住涉,實(shí)現(xiàn)自定義依賴。
@Provides
Coder provideCoder(Boss boss) {
return new Coder(boss);
}
include的用法
<pre style="margin: 8px 0px; background-color: rgb(43, 43, 43); color: rgb(169, 183, 198); font-family: 宋體; font-size: 0.8rem;">@Module (includes = {BModule.class})// includes 引入) public class AModule {
@Provides
A providerA() {
return new A();
}
}</pre>
@Named注解用
相當(dāng)于有個(gè)表示钠绍,雖然大家都是同一個(gè)對(duì)象舆声,但是實(shí)例化對(duì)象不同就不如
A a1 = new A(); A a2 = new A();// a1 a2 能一樣嘛
Module中 使用@Named
注解
@Module
public class MainModule {
private MainActivity activity;
public MainModule(MainActivity activity) {
this.activity = activity;
}
@Named("dev")
@Provides
MainApi provideMainApiDev(MainChildApi mainChildApi, String url) {
return new MainApi(mainChildApi, activity,"dev");
}
@Named("release")
@Provides
MainApi provideMainApiRelease(MainChildApi mainChildApi, String url) {
return new MainApi(mainChildApi, activity,"release");
}
}來(lái)源: http://www.reibang.com/p/2cd491f0da01
在Activity/Fragment中使用
<pre class="hljs java" style="margin: 8px 0px;">
<pre style="margin: 8px 0px; background-color: rgb(43, 43, 43); color: rgb(169, 183, 198); font-family: 宋體; font-size: 0.8rem;">public class MainActivity extends AppCompatActivity {
@Named("dev")
@Inject
MainApi apiDev; @Named("release")
@Inject
MainApi apiRelease; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); DaggerMainComponent.builder()
.mainModule(new MainModule(this))
.mainChildModule(new MainChildModule())
.build()
.inject(this);
apiDev.eat();
apiRelease.eat();
Log.i("TAG","apiDev--->" + apiDev);
Log.i("TAG","apiRelease--->" + apiRelease);
}
}</pre>
</pre>
<pre class="hljs java" style="margin: 8px 0px;">在項(xiàng)目中的應(yīng)用場(chǎng)景和實(shí)例:
</pre>
<pre class="hljs java" style="margin: 8px 0px;">https://blog.csdn.net/soslinken/article/details/52184113</pre>
注意:
實(shí)質(zhì)上,Dagger會(huì)在編譯時(shí)對(duì)代碼進(jìn)行檢查柳爽,并在檢查不通過(guò)的時(shí)候報(bào)編譯錯(cuò)誤(為什么媳握?這和Dagger的原理有關(guān),有興趣的話可以關(guān)注我之后發(fā)布的Dagger詳解)磷脯。檢查內(nèi)容主要有三點(diǎn):
- 所有含有依賴注入的類蛾找,需要被顯式 聲明在相應(yīng)的Module中。
- 一個(gè)Module中所有@Provides方法的參數(shù)都必須在這個(gè)Module種提供相應(yīng)的@Provides方法赵誓,或者在@Module注解后添加“complete = false”注明這是一個(gè)不完整Module(即它會(huì)被其他Module所擴(kuò)展)打毛。
- 一個(gè)Module中所有的@Provides方法都要被它聲明的注入對(duì)象所使用,或者在@Module注解后添加“l(fā)ibrary = ture”注明(即它是為了擴(kuò)展其他Module而存在的)俩功。
@Binds:的使用隘冲。
————————————————
總結(jié):
1.作用域--------重點(diǎn),比較難的地方绑雄!
2.組件依賴
3.子組件 subConponent
爬坑指南(極度重要)
- Provide 如果是單例模式 對(duì)應(yīng)的Compnent 也要是單例模式
- inject(Activity act) 不能放父類
- 即使使用了單利模式展辞,在不同的Activity 對(duì)象還是不一樣的
- 依賴component, component之間的Scoped 不能相同
- 子類component 依賴父類的component 万牺,子類component的Scoped 要小于父類的Scoped罗珍,Singleton的級(jí)別是Application
- 多個(gè)Moudle 之間不能提供相同的對(duì)象實(shí)例
- Moudle 中使用了自定義的Scoped 那么對(duì)應(yīng)的Compnent 使用同樣的Scoped
重點(diǎn)是:處理作用域provider
通過(guò)APT+javapoAT在編譯時(shí)候生成上面3個(gè)類洽腺!
APT的process()方法是什么時(shí)候執(zhí)行?
原理分析:
1.a是怎么實(shí)例化的
2.b和c是怎么是咧化的
3.他們是怎么綁定的
原理:在build里面生成了很多的類覆旱,工廠模式蘸朋,代理模式,A_Factory ,proxyProviderC
單列如何實(shí)現(xiàn)?
保持conponent是全局唯一的扣唱,通過(guò)application中初始化藕坯!
Dragger的原理:
[圖片上傳失敗...(image-115c54-1640679669730)]
1.DaggerPengConponnet------注入和對(duì)象的關(guān)系
在里面,通過(guò)工廠模式得到provider
就是下面要用的2個(gè)類PengModule_GetHttpObjectFactory和MainActivity_MembersInjector
<pre style="margin: 8px 0px; background-color: rgb(43, 43, 43); color: rgb(169, 183, 198); font-family: "JetBrains Mono", monospace; font-size: 0.817rem;">public final class DaggerPengConponnet implements PengConponnet {
private Provider<HttpObject> getHttpObjectProvider; private MembersInjector<MainActivity> mainActivityMembersInjector; private DaggerPengConponnet(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
public static PengConponnet create() {
return new Builder().build();
}
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.getHttpObjectProvider = PengModule_GetHttpObjectFactory.create(builder.pengModule); this.mainActivityMembersInjector = MainActivity_MembersInjector.create(getHttpObjectProvider);
}
@Override
public void injectActivity(MainActivity mainActivity) {
mainActivityMembersInjector.injectMembers(mainActivity);
}
public static final class Builder {
private PengModule pengModule; private Builder() {}
public PengConponnet build() {
if (pengModule == null) {
this.pengModule = new PengModule();
}
return new DaggerPengConponnet(this);
}
public Builder pengModule(PengModule pengModule) {
this.pengModule = Preconditions.checkNotNull(pengModule);
return this; }
}
}
</pre>
2.PengModule_GetHttpObjectFactory --------工廠噪沙,new出對(duì)象炼彪。
通過(guò)工廠模式創(chuàng)建對(duì)象
<pre style="margin: 8px 0px; background-color: rgb(43, 43, 43); color: rgb(169, 183, 198); font-family: "JetBrains Mono", monospace; font-size: 0.817rem;">public final class PengModule_GetHttpObjectFactory implements Factory<HttpObject> {
private final PengModule module; public PengModule_GetHttpObjectFactory(PengModule module) {
assert module != null;
this.module = module;
}
@Override
public HttpObject get() {
return Preconditions.checkNotNull(
module.getHttpObject(), "Cannot return null from a non-@Nullable @Provides method");
}
public static Factory<HttpObject> create(PengModule module) {
return new PengModule_GetHttpObjectFactory(module);
}
}3.MainActivity_MembersInjector -----賦值</pre>
通過(guò)provider得到了需要注入的對(duì)象
3.MainActivity_MembersInjector:注入綁定
<pre style="margin: 8px 0px; background-color: rgb(43, 43, 43); color: rgb(169, 183, 198); font-family: "JetBrains Mono", monospace; font-size: 0.817rem;">public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
private final Provider<HttpObject> httpObjectProvider; public MainActivity_MembersInjector(Provider<HttpObject> httpObjectProvider) {
assert httpObjectProvider != null;
this.httpObjectProvider = httpObjectProvider;
}
public static MembersInjector<MainActivity> create(Provider<HttpObject> httpObjectProvider) {
return new MainActivity_MembersInjector(httpObjectProvider);
}
@Override
public void injectMembers(MainActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.httpObject = httpObjectProvider.get();
}
public static void injectHttpObject(
MainActivity instance, Provider<HttpObject> httpObjectProvider) {
instance.httpObject = httpObjectProvider.get();
}
}</pre>
20211227最新使用:
[圖片上傳失敗...(image-cef848-1640679669730)]
使用4部曲
現(xiàn)在用Dagger2來(lái)改造,總體來(lái)說(shuō)就是4步:
- 1 在Adapter構(gòu)造器中加入@Inject注解(告訴他正歼,如何創(chuàng)建對(duì)象)
- 2 構(gòu)建 Module(不一定需要)
- 3 構(gòu)建 Component(聲明是dagger的組件辐马,傳入的參數(shù)是注入到哪里去)
- 4 完成依賴注入(調(diào)用完成注入)
在操作中會(huì)使用到了@Inject、@Module局义、@Provides喜爷、@Conponent注解,那么他們分別在完成什么工作萄唇?
MainActivityPresenter presenter = new MainActivityPresenter(this);
@Inject @Conponent @Module @Provides
這四個(gè)注解可以這么理解檩帐,@Inject承擔(dān)了=號(hào)左邊的工作,@Conponent 承擔(dān)了=號(hào)的工作另萤, @Module @Provides承擔(dān)了=號(hào)右邊的工作
自己的步驟理解:
1.本來(lái)就有的bean對(duì)象獲取其他對(duì)象httpObject
2.定義module:用來(lái)裝載上面的object,一個(gè)module可以有多個(gè)object
3.定義組件component: 用來(lái)裝module,一個(gè)component可以有多個(gè)module,一般是一個(gè)module.
4.使用湃密,在activty中,直接定義httpobject,然后oncreate通過(guò)注解注入就可以了仲墨。
具體代碼:
[圖片上傳失敗...(image-8e9472-1640679669730)]
第一步: Bean
<pre style="margin: 8px 0px; background-color: rgb(43, 43, 43); color: rgb(169, 183, 198); font-family: "JetBrains Mono", monospace; font-size: 0.817rem;">public class HttpObject {
}
</pre>
第二步:Module
<pre style="margin: 8px 0px; background-color: rgb(43, 43, 43); color: rgb(169, 183, 198); font-family: "JetBrains Mono", monospace; font-size: 0.817rem;">@Module public class PengModule {
@Provides
public HttpObject getHttpObject() {
return new HttpObject();
}
@Provides
public DatabaseObject getDatabase() {
return new DatabaseObject();
}
}
</pre>
第三步:Componet
<pre style="margin: 8px 0px; background-color: rgb(43, 43, 43); color: rgb(169, 183, 198); font-family: "JetBrains Mono", monospace; font-size: 0.817rem;">@Component(modules = PengModule.class) //可以有多個(gè)module public interface PengConponnet { // 接口給外部調(diào)用
void injectActivity(MainActivity mainActivity); }
</pre>
第四步:使用,需要用自動(dòng)生成的類
<pre style="margin: 8px 0px; background-color: rgb(43, 43, 43); color: rgb(169, 183, 198); font-family: "JetBrains Mono", monospace; font-size: 0.817rem;">public class MainActivity extends AppCompatActivity {
@Inject
HttpObject httpObject; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); //自動(dòng)生成類進(jìn)行注入
DaggerPengConponnet.create().injectActivity(this);
}
}
</pre>
非常不錯(cuò):