Android依賴(lài)注入框架Dagger2的使用方法
Dagger2注入框架原理簡(jiǎn)要分析
使用Dagger2需要的依賴(lài):
implementation 'com.google.dagger:dagger-android:2.46'
implementation 'com.google.dagger:dagger-android-support:2.46'
annotationProcessor 'com.google.dagger:dagger-android-processor:2.46'
annotationProcessor 'com.google.dagger:dagger-compiler:2.46'
示例代碼
這里先給出我的示例代碼,github上的demo點(diǎn)這里??
MainActivity
public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; @Inject Gson gson; @Inject Gson gson2; @Inject SwordMan swordMan; //@Inject //Car car; ActivityMainBinding myBinding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); myBinding = DataBindingUtil.setContentView(this, R.layout.activity_main); App.get(MainActivity.this).getActivityComponent().inject(this); onClick(); if(gson.hashCode() == gson2.hashCode()){ Toast.makeText(this, "Same", Toast.LENGTH_SHORT).show(); }else{ Toast.makeText(this, "Different", Toast.LENGTH_SHORT).show(); } myBinding.btTest2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this, swordMan.fighting(), Toast.LENGTH_SHORT).show(); } }); } private void onClick(){ myBinding.btTest1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(MainActivity.this,SecondActivity.class); startActivity(intent); } }); } }
SecondActivity
public class SecondActivity extends AppCompatActivity { ActivitySecondBinding S_Binding; @Inject Lazy<SwordMan> swordManLazy;//實(shí)現(xiàn)懶加載 SwordMan swordMan = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); S_Binding = DataBindingUtil.setContentView(this,R.layout.activity_second); App.get(SecondActivity.this).getActivityComponent().inject(this); if(swordMan == null){ Toast.makeText(this, "暫未初始化", Toast.LENGTH_SHORT).show(); } swordMan = swordManLazy.get(); //setContentView(R.layout.activity_second); S_Binding.button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(SecondActivity.this, swordMan.fighting(), Toast.LENGTH_SHORT).show(); } }); } }
App
注意App類(lèi)需要在manifest清單文件中聲明。
public class App extends Application { ActivityComponent activityComponent; @Override public void onCreate() { super.onCreate(); activityComponent = DaggerActivityComponent.builder().swordmanComponent(DaggerSwordmanComponent.builder().build()) .build(); } public static App get(Context context){ return (App) context.getApplicationContext(); } ActivityComponent getActivityComponent(){ return activityComponent; } }
Component類(lèi)
@ApplicationScope @Component(modules = GsonModule.class,dependencies = SwordmanComponent.class) public interface ActivityComponent { void inject(MainActivity activity); void inject(SecondActivity activity); } @Component(modules = SwordmanModule.class) public interface SwordmanComponent { SwordMan getSwordman(); }
Module類(lèi)以及實(shí)體類(lèi)
@Module public class GsonModule { @ApplicationScope @Provides public Gson provideGson(){ return new Gson(); } } @Module public class SwordmanModule { @Provides public SwordMan provideSwordman(){ return new SwordMan(); } } public class SwordMan { @Inject public SwordMan(){ } public String fighting(){ return "欲為大樹(shù),莫于草爭(zhēng)"; } }
生成代碼分析
Dagger2是通過(guò)注解生成中間類(lèi)的方式幫我們注入依賴(lài)的,我們就來(lái)分析它生成的中間類(lèi)的代碼。
由于注入器是在App類(lèi)中初始化的,所以我們先從App類(lèi)開(kāi)始看,App類(lèi)中最重要的無(wú)非就是這一句:
activityComponent = DaggerActivityComponent.builder().swordmanComponent(DaggerSwordmanComponent.builder().build()) .build();
通過(guò)DaggerActivityComonent以及builder的配置生成了一個(gè)注入器接口的實(shí)現(xiàn)類(lèi),所以我們先看DaggerActivityComponent類(lèi)
DaggerActivityComponent類(lèi)
public final class DaggerActivityComponent { private DaggerActivityComponent() { } public static Builder builder() { return new Builder(); } public static final class Builder { private GsonModule gsonModule; private SwordmanComponent swordmanComponent; private Builder() { } public Builder gsonModule(GsonModule gsonModule) { this.gsonModule = Preconditions.checkNotNull(gsonModule); return this; } public Builder swordmanComponent(SwordmanComponent swordmanComponent) { this.swordmanComponent = Preconditions.checkNotNull(swordmanComponent); return this; } public ActivityComponent build() { if (gsonModule == null) { this.gsonModule = new GsonModule(); } Preconditions.checkBuilderRequirement(swordmanComponent, SwordmanComponent.class); return new ActivityComponentImpl(gsonModule, swordmanComponent); } } private static final class ActivityComponentImpl implements ActivityComponent { ... } }
我們先來(lái)看前面有關(guān)Builder的方法,由于我們?cè)贏ctivity的Component注解中添加了modules和dependencies的值,所以在builder中就會(huì)生成響應(yīng)的gsonModule(GsonModule gsonModule)和swordmanComponent(SwordmanComponent swordmanComponent)方法,這兩個(gè)方法分別是用來(lái)設(shè)置生成的注入器中的gsonModule和swordmanComponent對(duì)象的。
通過(guò)App類(lèi)中的調(diào)用的代碼我們可以發(fā)現(xiàn),對(duì)于注解中的modules,我們?cè)趧?chuàng)建注入器的時(shí)候是不需要手動(dòng)添加的,但是對(duì)dependencies注解來(lái)說(shuō)就需要手動(dòng)添加:
DaggerActivityComponent.builder().swordmanComponent(DaggerSwordmanComponent.builder().build()) .build();//手動(dòng)添加了DaggerSwordmanComponent的注入器
builder中的Preconditions.checkNotNull()只是用來(lái)判空的,總的來(lái)說(shuō),builder這個(gè)內(nèi)部類(lèi)就是用來(lái)幫助構(gòu)建注入器實(shí)例的。所以我們接下來(lái)就來(lái)看這個(gè)注入器實(shí)例:
private static final class ActivityComponentImpl implements ActivityComponent { private final SwordmanComponent swordmanComponent; private final ActivityComponentImpl activityComponentImpl = this; private Provider<Gson> provideGsonProvider; private Provider<SwordMan> getSwordmanProvider; private ActivityComponentImpl(GsonModule gsonModuleParam, SwordmanComponent swordmanComponentParam) { this.swordmanComponent = swordmanComponentParam; initialize(gsonModuleParam, swordmanComponentParam); } @SuppressWarnings("unchecked") private void initialize(final GsonModule gsonModuleParam, final SwordmanComponent swordmanComponentParam) { this.provideGsonProvider = DoubleCheck.provider(GsonModule_ProvideGsonFactory.create(gsonModuleParam)); this.getSwordmanProvider = new GetSwordmanProvider(swordmanComponentParam); } @Override public void inject(MainActivity activity) { injectMainActivity(activity); } @Override public void inject(SecondActivity activity) { injectSecondActivity(activity); } private MainActivity injectMainActivity(MainActivity instance) { ... } private SecondActivity injectSecondActivity(SecondActivity instance) { ... } private static final class GetSwordmanProvider implements Provider<SwordMan> { ... } }
先不看最后一個(gè)內(nèi)部類(lèi),先看注入器類(lèi)ActivityComponentImpl 實(shí)現(xiàn)了 ActivityComponent 接口,也就是說(shuō)它就是實(shí)際的注入器類(lèi),這個(gè)類(lèi)的構(gòu)造方法是私有的,說(shuō)明只能通過(guò)構(gòu)造器來(lái)構(gòu)造實(shí)例。先關(guān)注它的構(gòu)造方法,構(gòu)造方法傳入的參數(shù)正是我們?cè)贑omponent接口的注解中寫(xiě)入的值:
@Component(modules = GsonModule.class,dependencies = SwordmanComponent.class) ... private void initialize(final GsonModule gsonModuleParam, final SwordmanComponent swordmanComponentParam){ ... }
傳入了一個(gè)GsonModule和一個(gè)SwordmanComponent,和目前這個(gè)ActivityComponent類(lèi)似,這個(gè)SwordmanComponent肯定也是有一個(gè)實(shí)現(xiàn)類(lèi)的,我們后面再看這兩個(gè)類(lèi)的具體內(nèi)容。
接著我們接續(xù)看它的注入依賴(lài)的方法,我們?cè)谧⑷胍蕾?lài)時(shí),顯然是用到了inject方法,對(duì)應(yīng)不同的注入對(duì)象,將會(huì)調(diào)用不同的inject的重載方法,我們先看MainActivity的注入方法:
private MainActivity injectMainActivity(MainActivity instance) { MainActivity_MembersInjector.injectGson(instance, provideGsonProvider.get()); MainActivity_MembersInjector.injectGson2(instance, provideGsonProvider.get()); MainActivity_MembersInjector.injectSwordMan(instance, Preconditions.checkNotNullFromComponent(swordmanComponent.getSwordman())); return instance; }
injectMainActivity中分別調(diào)用了注入的方法,很顯然,就是將我們?cè)贛ainActivity中標(biāo)記為需要注入的變量給注入?yún)?shù),我們接下來(lái)看這個(gè)MainActivity_MembersInjector中間類(lèi)。
MainActivity_MembersInjector
就這個(gè)類(lèi)的命名來(lái)說(shuō),它應(yīng)該是具體負(fù)責(zé)成員變量注入依賴(lài)的注入器。前面說(shuō)到在ActivityComponentImpl調(diào)用了它的injectGson等方法,我們來(lái)看這三個(gè)方法:
@InjectedFieldSignature("com.example.dagger2demo.activitys.MainActivity.gson") public static void injectGson(MainActivity instance, Gson gson) { instance.gson = gson; } @InjectedFieldSignature("com.example.dagger2demo.activitys.MainActivity.gson2") public static void injectGson2(MainActivity instance, Gson gson2) { instance.gson2 = gson2; } @InjectedFieldSignature("com.example.dagger2demo.activitys.MainActivity.swordMan") public static void injectSwordMan(MainActivity instance, SwordMan swordMan) { instance.swordMan = swordMan; }
看到這里,這三個(gè)方法的作用已經(jīng)非常明顯了,將我們需要注入依賴(lài)的對(duì)象傳入這三個(gè)方法中,方法就會(huì)給需要注入依賴(lài)對(duì)象中標(biāo)記為@Inject的成員變量賦值。至于這個(gè)@InjectedFieldSignature注解,@InjectedFieldSignature注解是Dagger中的一個(gè)自定義注解,用于幫助Dagger在運(yùn)行時(shí)自動(dòng)生成代碼以實(shí)現(xiàn)依賴(lài)注入。它用于標(biāo)記要進(jìn)行依賴(lài)注入的字段,并提供了一個(gè)字符串參數(shù),用于標(biāo)識(shí)該字段所依賴(lài)的對(duì)象的類(lèi)型。在運(yùn)行時(shí),Dagger會(huì)掃描這些注解并自動(dòng)生成相應(yīng)的代碼,以實(shí)現(xiàn)將依賴(lài)注入到被標(biāo)記的字段中。
何處真正產(chǎn)生了實(shí)際參數(shù)
這時(shí)候新的問(wèn)題產(chǎn)生了,這些被注入的參數(shù)是在哪里被初始化的呢,換句話說(shuō),injectGson()方法中的第二個(gè)參數(shù)gson是在哪里被開(kāi)辟空間的呢,答案就在之前的ActivityComponentImpl中:
private MainActivity injectMainActivity(MainActivity instance) { MainActivity_MembersInjector.injectGson(instance, provideGsonProvider.get()); ... }
從這里可以看出,這個(gè)實(shí)際被注入的參數(shù)是由provideGsonProvider的get方法提供的:
@SuppressWarnings("unchecked") private void initialize(final GsonModule gsonModuleParam, final SwordmanComponent swordmanComponentParam) { this.provideGsonProvider = DoubleCheck.provider(GsonModule_ProvideGsonFactory.create(gsonModuleParam)); this.getSwordmanProvider = new GetSwordmanProvider(swordmanComponentParam); } ... public final class GsonModule_ProvideGsonFactory implements Factory<Gson> { private final GsonModule module; public GsonModule_ProvideGsonFactory(GsonModule module) { this.module = module; } @Override public Gson get() { return provideGson(module); } public static GsonModule_ProvideGsonFactory create(GsonModule module) { return new GsonModule_ProvideGsonFactory(module); } public static Gson provideGson(GsonModule instance) { return Preconditions.checkNotNullFromProvides(instance.provideGson()); } }
這里DoubleCheck 是 Dagger2 中的一個(gè)工具類(lèi),用于確保依賴(lài)只被創(chuàng)建一次,具體來(lái)說(shuō),由于我們?cè)谧⑷肫鹘涌谥袠?biāo)記了被注入?yún)?shù)的作用域,所以會(huì)調(diào)用DoubleCheck方法。緊接著我們看GsonModule_ProvideGsonFactory,很顯然實(shí)現(xiàn)調(diào)用了create方法,但是create方法又是實(shí)際調(diào)用了GsonModule_ProvideGsonFactory的構(gòu)造方法,這里傳入了GsonModule類(lèi),還記得GsonModule類(lèi)嗎?正是我們自己寫(xiě)的實(shí)例提供者。
現(xiàn)在我們繼續(xù)返回到ActivityComponentImpl中,看這個(gè)GsonModule的實(shí)例在哪里,答案在builder中。我們先一個(gè)一個(gè)往前捋:
首先在initialize方法中調(diào)用了create:
this.provideGsonProvider = DoubleCheck.provider(GsonModule_ProvideGsonFactory.create(gsonModuleParam))
所以我們需要看initialize方法中傳入的GsonModule實(shí)例來(lái)自哪里,是來(lái)自ActivityComponentImpl的構(gòu)造方法中:
private ActivityComponentImpl(GsonModule gsonModuleParam, SwordmanComponent swordmanComponentParam) { this.swordmanComponent = swordmanComponentParam; initialize(gsonModuleParam, swordmanComponentParam); }
那這個(gè)構(gòu)造方法中的GsonModule來(lái)自哪里呢,之前我們提到過(guò),由于這個(gè)構(gòu)造方法是私有的,所以我們只能通過(guò)構(gòu)造器builder來(lái)創(chuàng)建,所以答案顯然是在builder這個(gè)內(nèi)部類(lèi)中:
public ActivityComponent build() { if (gsonModule == null) { this.gsonModule = new GsonModule(); } Preconditions.checkBuilderRequirement(swordmanComponent, SwordmanComponent.class); return new ActivityComponentImpl(gsonModule, swordmanComponent); }
這個(gè)GsonModule類(lèi)的實(shí)例正是調(diào)用了我們寫(xiě)的GsonModule的構(gòu)造方法,所以我們可以畫(huà)出傳遞的流程圖:
簡(jiǎn)要流程圖(僅適用于本示例)
簡(jiǎn)而言之,Dagger2正是通過(guò)APT和生成的中間件代碼來(lái)實(shí)現(xiàn)依賴(lài)注入的。
到此這篇關(guān)于Android依賴(lài)注入框架Dagger2的使用方法的文章就介紹到這了,更多相關(guān)Android Dagger2內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android中ListActivity用法實(shí)例分析
這篇文章主要介紹了Android中ListActivity用法,結(jié)合實(shí)例形式較為詳細(xì)的分析了ListActivity功能,注意事項(xiàng)與相關(guān)使用技巧,需要的朋友可以參考下2016-02-02Android 中為什么要用Fragment.setArguments(Bundle bundle)來(lái)傳遞參數(shù)
這篇文章主要介紹了Android 中為什么要用Fragment.setArguments(Bundle bundle)來(lái)傳遞參數(shù),非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下2017-01-01android studio實(shí)現(xiàn)簡(jiǎn)單的計(jì)算器功能
這篇文章主要為大家詳細(xì)介紹了android studio實(shí)現(xiàn)簡(jiǎn)單的計(jì)算器功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05Andriod arcgis保存Mapview為圖片的實(shí)例代碼
這篇文章主要介紹了Andriod arcgis保存Mapview為圖片的實(shí)例代碼 的相關(guān)資料,需要的朋友可以參考下2016-03-03Android TextWatcher三個(gè)回調(diào)以及監(jiān)聽(tīng)EditText的輸入案例詳解
這篇文章主要介紹了Android TextWatcher三個(gè)回調(diào)以及監(jiān)聽(tīng)EditText的輸入案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08Android中使用TagFlowLayout制作動(dòng)態(tài)添加刪除標(biāo)簽
這篇文章主要介紹了Android中使用TagFlowLayout制作動(dòng)態(tài)添加刪除標(biāo)簽的步驟詳解,需要的朋友參考下吧2017-07-07