Android依賴注入框架Dagger2的使用方法
Dagger2注入框架原理簡要分析
使用Dagger2需要的依賴:
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點這里??
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;//實現(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類需要在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類
@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類以及實體類
@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 "欲為大樹,莫于草爭";
}
}生成代碼分析
Dagger2是通過注解生成中間類的方式幫我們注入依賴的,我們就來分析它生成的中間類的代碼。
由于注入器是在App類中初始化的,所以我們先從App類開始看,App類中最重要的無非就是這一句:
activityComponent =
DaggerActivityComponent.builder().swordmanComponent(DaggerSwordmanComponent.builder().build())
.build();通過DaggerActivityComonent以及builder的配置生成了一個注入器接口的實現(xiàn)類,所以我們先看DaggerActivityComponent類
DaggerActivityComponent類
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 {
...
}
}我們先來看前面有關Builder的方法,由于我們在Activity的Component注解中添加了modules和dependencies的值,所以在builder中就會生成響應的gsonModule(GsonModule gsonModule)和swordmanComponent(SwordmanComponent swordmanComponent)方法,這兩個方法分別是用來設置生成的注入器中的gsonModule和swordmanComponent對象的。
通過App類中的調(diào)用的代碼我們可以發(fā)現(xiàn),對于注解中的modules,我們在創(chuàng)建注入器的時候是不需要手動添加的,但是對dependencies注解來說就需要手動添加:
DaggerActivityComponent.builder().swordmanComponent(DaggerSwordmanComponent.builder().build())
.build();//手動添加了DaggerSwordmanComponent的注入器builder中的Preconditions.checkNotNull()只是用來判空的,總的來說,builder這個內(nèi)部類就是用來幫助構建注入器實例的。所以我們接下來就來看這個注入器實例:
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> {
...
}
}先不看最后一個內(nèi)部類,先看注入器類ActivityComponentImpl 實現(xiàn)了 ActivityComponent 接口,也就是說它就是實際的注入器類,這個類的構造方法是私有的,說明只能通過構造器來構造實例。先關注它的構造方法,構造方法傳入的參數(shù)正是我們在Component接口的注解中寫入的值:
@Component(modules = GsonModule.class,dependencies = SwordmanComponent.class)
...
private void initialize(final GsonModule gsonModuleParam,
final SwordmanComponent swordmanComponentParam){
...
}傳入了一個GsonModule和一個SwordmanComponent,和目前這個ActivityComponent類似,這個SwordmanComponent肯定也是有一個實現(xiàn)類的,我們后面再看這兩個類的具體內(nèi)容。
接著我們接續(xù)看它的注入依賴的方法,我們在注入依賴時,顯然是用到了inject方法,對應不同的注入對象,將會調(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)用了注入的方法,很顯然,就是將我們在MainActivity中標記為需要注入的變量給注入?yún)?shù),我們接下來看這個MainActivity_MembersInjector中間類。
MainActivity_MembersInjector
就這個類的命名來說,它應該是具體負責成員變量注入依賴的注入器。前面說到在ActivityComponentImpl調(diào)用了它的injectGson等方法,我們來看這三個方法:
@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;
}看到這里,這三個方法的作用已經(jīng)非常明顯了,將我們需要注入依賴的對象傳入這三個方法中,方法就會給需要注入依賴對象中標記為@Inject的成員變量賦值。至于這個@InjectedFieldSignature注解,@InjectedFieldSignature注解是Dagger中的一個自定義注解,用于幫助Dagger在運行時自動生成代碼以實現(xiàn)依賴注入。它用于標記要進行依賴注入的字段,并提供了一個字符串參數(shù),用于標識該字段所依賴的對象的類型。在運行時,Dagger會掃描這些注解并自動生成相應的代碼,以實現(xiàn)將依賴注入到被標記的字段中。
何處真正產(chǎn)生了實際參數(shù)
這時候新的問題產(chǎn)生了,這些被注入的參數(shù)是在哪里被初始化的呢,換句話說,injectGson()方法中的第二個參數(shù)gson是在哪里被開辟空間的呢,答案就在之前的ActivityComponentImpl中:
private MainActivity injectMainActivity(MainActivity instance) {
MainActivity_MembersInjector.injectGson(instance, provideGsonProvider.get());
...
}從這里可以看出,這個實際被注入的參數(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 中的一個工具類,用于確保依賴只被創(chuàng)建一次,具體來說,由于我們在注入器接口中標記了被注入?yún)?shù)的作用域,所以會調(diào)用DoubleCheck方法。緊接著我們看GsonModule_ProvideGsonFactory,很顯然實現(xiàn)調(diào)用了create方法,但是create方法又是實際調(diào)用了GsonModule_ProvideGsonFactory的構造方法,這里傳入了GsonModule類,還記得GsonModule類嗎?正是我們自己寫的實例提供者。
現(xiàn)在我們繼續(xù)返回到ActivityComponentImpl中,看這個GsonModule的實例在哪里,答案在builder中。我們先一個一個往前捋:
首先在initialize方法中調(diào)用了create:
this.provideGsonProvider = DoubleCheck.provider(GsonModule_ProvideGsonFactory.create(gsonModuleParam))
所以我們需要看initialize方法中傳入的GsonModule實例來自哪里,是來自ActivityComponentImpl的構造方法中:
private ActivityComponentImpl(GsonModule gsonModuleParam,
SwordmanComponent swordmanComponentParam) {
this.swordmanComponent = swordmanComponentParam;
initialize(gsonModuleParam, swordmanComponentParam);
}那這個構造方法中的GsonModule來自哪里呢,之前我們提到過,由于這個構造方法是私有的,所以我們只能通過構造器builder來創(chuàng)建,所以答案顯然是在builder這個內(nèi)部類中:
public ActivityComponent build() {
if (gsonModule == null) {
this.gsonModule = new GsonModule();
}
Preconditions.checkBuilderRequirement(swordmanComponent, SwordmanComponent.class);
return new ActivityComponentImpl(gsonModule, swordmanComponent);
}這個GsonModule類的實例正是調(diào)用了我們寫的GsonModule的構造方法,所以我們可以畫出傳遞的流程圖:
簡要流程圖(僅適用于本示例)

簡而言之,Dagger2正是通過APT和生成的中間件代碼來實現(xiàn)依賴注入的。
到此這篇關于Android依賴注入框架Dagger2的使用方法的文章就介紹到這了,更多相關Android Dagger2內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Android 中為什么要用Fragment.setArguments(Bundle bundle)來傳遞參數(shù)
這篇文章主要介紹了Android 中為什么要用Fragment.setArguments(Bundle bundle)來傳遞參數(shù),非常不錯,具有參考借鑒價值,需要的朋友參考下2017-01-01
android studio實現(xiàn)簡單的計算器功能
這篇文章主要為大家詳細介紹了android studio實現(xiàn)簡單的計算器功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-05-05
Andriod arcgis保存Mapview為圖片的實例代碼
這篇文章主要介紹了Andriod arcgis保存Mapview為圖片的實例代碼 的相關資料,需要的朋友可以參考下2016-03-03
Android TextWatcher三個回調(diào)以及監(jiān)聽EditText的輸入案例詳解
這篇文章主要介紹了Android TextWatcher三個回調(diào)以及監(jiān)聽EditText的輸入案例詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下2021-08-08
Android中使用TagFlowLayout制作動態(tài)添加刪除標簽
這篇文章主要介紹了Android中使用TagFlowLayout制作動態(tài)添加刪除標簽的步驟詳解,需要的朋友參考下吧2017-07-07

