看一個(gè)簡(jiǎn)單dagger2的Demo1
目標(biāo)類B
public class B { @Inject public B() { } public String getName(){ return "BBBBBBB"; }}頁面Activitypublic class MainActivity extends BaseActivity { @Inject B b; @Override PRotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //實(shí)例化component對(duì)象,注意DaggerBComponent是生成的,所以打這行代碼時(shí),先編譯一下 BComponent component = DaggerBComponent.builder().build(); //注入 component.injectB(this); Log.e("-------","通過inject來實(shí)現(xiàn)======"+b.getName()); }}@Componentpublic interface BComponent { void injectB(Main2Activity activity);}運(yùn)行,打印的結(jié)果為"通過...======BBBBBBB"
其中Inject注解(Annotation)來標(biāo)注目標(biāo)類中所依賴的其他類(MainActivity中的B),同樣用注解來標(biāo)注所依賴的其他類的構(gòu)造函數(shù)(B的構(gòu)造方法)
1:用Inject注解標(biāo)注目標(biāo)類中的其他類(MainActivity中的屬性B)
2:用Inject注解標(biāo)注其他類的構(gòu)造方法(B類的構(gòu)造方法)
3:用Inject注解標(biāo)注屬性時(shí),屬性不能用private修飾,不然會(huì)報(bào)錯(cuò),如下:
Error:(13, 20) 錯(cuò)誤: Dagger does not support injection into private fields原因是Dagger2是采用編譯時(shí)產(chǎn)生注入代碼(一個(gè)注入工具類)來為變量注入值,注入過程如下所示:
public void injectMembers(MainActivity instance) { if (instance == null) { throw new NullPointerException("Cannot inject members into a null reference"); } supertypeInjector.injectMembers(instance); instance.str = strProvider.get();//為變量str注入值,若變量str為private,此處就無法引用到str}補(bǔ)充:inject還可以標(biāo)注在方法里,使用@Inject注解提供依賴的方式是在這個(gè)類的public方法中作注解:
public class LoginActivityPresenter { private LoginActivity loginActivity; @Inject public LoginActivityPresenter(LoginActivity loginActivity) { this.loginActivity = loginActivity; } @Inject public void enableWatches(Watches watches) { watches.register(this); //Watches instance required fully constructed LoginActivityPresenter }}方法的所有參數(shù)都是通過依賴圖表提供的。但是為什么我們需要方法注入呢?在某些情況下會(huì)用到,如當(dāng)我們希望傳入類的當(dāng)前實(shí)例(this引用)到被注入的依賴中。方法注入會(huì)在構(gòu)造器調(diào)用后馬上被調(diào)用,所以這表示我們可以傳入完全被構(gòu)造的this。因?yàn)閑nableWatches方法里需要用到LoginActivityPresenter對(duì)象實(shí)例,而用inject標(biāo)注這個(gè)方法的作用在于,當(dāng)這個(gè)構(gòu)造方法被調(diào)用時(shí),會(huì)把這個(gè)實(shí)例傳給watches.register(this)中去.
其中Component也是一個(gè)注解類,一個(gè)類要想是Component,
1:必須用Component注解來標(biāo)注該類
2:該類是接口或抽象類
3:方法名必須是injectXXX(Object),參數(shù)object是表示你要注入到哪里去,這里不能寫父類BaseActivity,因?yàn)榫唧w寫了哪個(gè)類,它就到哪個(gè)類中找Inject標(biāo)注的屬性
上文中提到Component在目標(biāo)類中所依賴的其他類與其他類的構(gòu)造函數(shù)之間可以起到一個(gè)橋梁的作用。
這個(gè)demo中component的工作原理是:
Component會(huì)查找MainActivity中用Inject注解標(biāo)注的屬性(B),查找到相應(yīng)的屬性后會(huì)接著查找該屬性(B)對(duì)應(yīng)的用Inject標(biāo)注的構(gòu)造函數(shù)(這時(shí)候就發(fā)生聯(lián)系了),剩下的工作就是初始化該屬性的實(shí)例并把實(shí)例進(jìn)行賦值。因此我們也可以給Component叫另外一個(gè)名字注入器(Injector)
Demo1還有種是對(duì)象B的構(gòu)造方法是由參數(shù)的,那么又應(yīng)該怎么弄呢?后面會(huì)有說明
引出Module類
項(xiàng)目中使用到了第三方的類庫(kù),第三方類庫(kù)又不能修改,所以根本不可能把Inject注解加入這些類中,這時(shí)我們的Inject就失效了。
那么就需要封裝第三方的類庫(kù),封裝的代碼怎么管理呢,總不能讓這些封裝的代碼散落在項(xiàng)目中的任何地方,總得有個(gè)好的管理機(jī)制,那Module就可以擔(dān)當(dāng)此任。可以把封裝第三方類庫(kù)的代碼放入Module中,像Demo2:
目標(biāo)類A
public class A { String aa = "小花";//注意這里沒有用inject標(biāo)注 public A() { }}Moudle類(類名命名木有要求)
@Modulepublic class AModule { @Provides A providesA(){ return new A(); }}Component類(類名命名木有要求)
@Component(modules = {AModule.class})public interface AComponent { void inject(NewActivity act);}頁面NewActivity
public class NewActivity extends AppCompatActivity { @Inject A a1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_new); //實(shí)例化component對(duì)象 AComponent component = DaggerAComponent.builder().aModule(new AModule()).build(); //注入 component.inject(this); Log.e("---------",a1.aa); }}打印結(jié)果:小花
其中,Module類其實(shí)是簡(jiǎn)單工廠模式,類里面基本都是創(chuàng)建類實(shí)例的方法
這時(shí)Component是怎樣的工作原理:
Component是注入器,它一端連接目標(biāo)類,另一端連接目標(biāo)類依賴實(shí)例,它把目標(biāo)類依賴實(shí)例注入到目標(biāo)類中。上文中的Module是一個(gè)提供類實(shí)例的類,所以Module應(yīng)該是屬于Component的實(shí)例端的(連接各種目標(biāo)類依賴實(shí)例的端),Component的新職責(zé)就是管理好Module,Component中的modules屬性可以把Module加入Component,modules可以加入多個(gè)Module。
Module中的創(chuàng)建類實(shí)例方法用Provides進(jìn)行標(biāo)注,Component在搜索到目標(biāo)類中用Inject注解標(biāo)注的屬性后,Component就會(huì)去Module中去查找用Provides標(biāo)注的對(duì)應(yīng)的創(chuàng)建類實(shí)例方法,這樣就可以解決第三方類庫(kù)用dagger2實(shí)現(xiàn)依賴注入了。
那么問題來了,如果實(shí)例D的構(gòu)造也用@Inject標(biāo)注的話,這時(shí)Component應(yīng)該怎么作為橋梁的呢?
首先Component會(huì)搜索目標(biāo)類中用Inject標(biāo)注的屬性(B),然后如果有Module類,就會(huì)先從Module類中找,看有沒有用@Provides標(biāo)注的方法,是否提供了這個(gè)實(shí)例,有則創(chuàng)建返回;沒有的話,就去看這個(gè)實(shí)例(B)的構(gòu)造方法是否Inject標(biāo)注,有則,創(chuàng)建返回;也就是說,Component會(huì)先去從Module中找,沒有的話,才去構(gòu)造中找
注意:Component可以包含一個(gè)或多個(gè)Module類,也可以不包含,Demo1即使不包含
如果構(gòu)造是有參數(shù)的,Component應(yīng)該怎么連接?
public class D { String name = "卡卡卡"; public D(B b) { }}以下是初始化目標(biāo)類的具體步驟
步驟1:查找Module中是否存在創(chuàng)建該類的方法。步驟2:若存在創(chuàng)建類方法,查看該方法是否存在參數(shù) 步驟2.1:若存在參數(shù),則按從**步驟1**開始依次初始化每個(gè)參數(shù) 步驟2.2:若不存在參數(shù),則直接初始化該類實(shí)例,一次依賴注入到此結(jié)束步驟3:若不存在創(chuàng)建類方法,則查找Inject注解的構(gòu)造函數(shù), 看構(gòu)造函數(shù)是否存在參數(shù) 步驟3.1:若存在參數(shù),則從**步驟1**開始依次初始化每個(gè)參數(shù) 步驟3.2:若不存在參數(shù),則直接初始化該類實(shí)例,一次依賴注入到此結(jié)束注意:如果參數(shù)沒有從module中找到,其構(gòu)造又未被inject標(biāo)注,則會(huì)報(bào)錯(cuò)
所以:在module中,不要出現(xiàn)參數(shù)和返回值一樣,如上所述的話,會(huì)造成死循環(huán)
總結(jié):
Inject,Component,Module,Provides是dagger2中的最基礎(chǔ)最核心的知識(shí)點(diǎn)。奠定了dagger2的整個(gè)依賴注入框架。
Inject主要是用來標(biāo)注目標(biāo)類的依賴和依賴的構(gòu)造函數(shù)Component它是一個(gè)橋梁,一端是目標(biāo)類,另一端是目標(biāo)類所依賴類的實(shí)例,它也是注入器(Injector)負(fù)責(zé)把目標(biāo)類所依賴類的實(shí)例注入到目標(biāo)類中,同時(shí)它也管理Module。Module和Provides是為解決第三方類庫(kù)而生的,Module是一個(gè)簡(jiǎn)單工廠模式,Module可以包含創(chuàng)建類實(shí)例的方法,這些方法用Provides來標(biāo)注
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注