學習札記:Dagger2快速上手系列一
學習札記:Dagger2快速上手系列二
上文我們簡單的介紹了Dagger2的的快速使用,
這篇文章來說一說Dagger2的一些坑和注意事項。
1.@Named註解的使用
Dagger2中用@Name來依賴注入的對象做限定,這句話是什麼意思呢,也就是說比如我們在上文的例子中,我們通過依賴注入返回SUserManager對象,如果此時我們需要返回兩個不同這個對象,我們在SUserModule返回的只有一個,這個時候我們在依賴注入的地方和Module的工廠方法中加入同樣的這個Name註解,就可以區分返回不同的對象了。Named這個註解本身是可以有參數,也可以通過自定義註解用Qualifier來註解這個自定義註解,因爲Named這個註解就是用Qualifier這個註解的註解,下面通過代碼看一看.
容器中的代碼:
public class MainActivity extends AppCompatActivity {
@Named("release")
@Inject
SUserManager daggerUserManager;
@Named("debug")
@Inject
SUserManager daggerUserManagerDebug;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerSUserComponent.create().inject(this);
daggerUserManager.register();
}
}
工廠中的代碼
public class SUserModule{
@Provides
public SUserStore provideSuserStrore() {
return new SUserStore ();
}
@Provides
public SApiService provideApiService() {
return new SApiService();
}
@Named("release")
@Provides
public SUserManager provideUserManager(SApiService apiService, SUserStore userStore) {
return new SUserManager(apiService, userStore);
}
@Named("debug")
@Provides
public SUserManager provideUserManagerForDebug(SApiService apiService, SUserStore userStore) {
return new SUserManager(apiService, userStore);
}
}
2.作用域的坑
舉個簡單的例子,比如我們在網絡請求的時候,假設我們用到了一個OkHttpClient,我們在創建了一個新的Module,並提供了提供了一個實例,然後在需要注入的時候 用@Inject就可以使用了:
@Module
public class SUserModule{
/*...
省略其他代碼
...*/
@Singleton
@Provides
public OkHttpClient provideOkHttoClinet(){
return new OkHttpClient.Builder().build();
}
}
這樣咋一看沒有什麼問題,但是我們每次用到這個得時候,都會重新創建一遍OkHttpClient,這樣就造成了性能的消耗,這個時候Dagger2爲我們增加了一個 @Singleton來表明這個OkHttpClient是個單例,但是實際上,他只是做容器內的單例,也就是我們在MainActivity中使用OkHttpClient時,他是個單例,在另外的Activity中,比如登錄的Acvitity,它又重新被創建了,那怎麼辦才能做到唯一呢,因爲@Singleton是依附於Component的,一般的情況下,我們會寫個App的Component,在Application的初始化中去注入進去。讓其他的Component去依賴這個AppComponent,下面請看下代碼,
我們在AppComponent中提供獲取單例的OkHttpClient的聲明。
@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
OkHttpClient okHttoClinet();
}
我們在AppModule中實例化OkHttpClent,這個時候SUserModule裏面的OkHttpClient就可以去掉了。
@Module
public class AppModule {
@Singleton
@Provides
public OkHttpClient provideOkHttpClient(){
return new OkHttpClient();
}
}
我們在Application中初始化AppComponent
public class MyApplication exntends Application{
private AppComponent appComponent;
public AppComponent getAppComponent(){
return appComponent;
}
@Override
protected onCreate(){
super.onCreate();
appComponent=DaggerAppComponent().create();
}
}
我們讓其他Component依賴於AppComponent,需要注意的是.由於AppComponent已經用了@Singleton這個註解來註解AppComponent了,所以在SUserComponent中需要用一個自定義scope來註解當前的Component,即有dependencies關係的組件之間的scope是不能相同的。
@ActivityScope
@Component(modules = {SUserModule.class,dependencies=AppComponent.class})
public interface SUserComponent {
void inject(MainActivity activity);
}
自定義的scope
package com.android.seven.dagger2.dagger;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import javax.inject.Scope;
import javax.inject.Singleton;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Scope
@Documented
@Retention(RUNTIME)
public @interface ActivityScope {
}
3,其他需要注意的地方
a.Component中需要inject的地方不能使用父類替換子類作爲參數,這個是註解迷失的坑。舉個例子比如在SUerComponent中的inject(MainActivity activity);這個方法中MainActivity不能用器父類替換,只能是MainActivity;
b.Component關聯的modules中不能有重複的provides,也就是關聯的多個module不能提供相同的對象;
b.module中provide,如果使用了scope,則component必須與其一致,比如AppComponent,如果module中provide沒有使用scope,則component無所謂,如果說component有dependencies關係,scope必須不一樣,即有依賴關係的component不一樣;
c.Sigleton的component不能依賴其他組件;
d.沒有scope的component不能依賴有scope的component;
e.一個component不能有多個scope(subComponent除外)
f.sigleton的生命週期依附於component。
暫時只整理這麼多,本文如果有不正之處,煩請之處,感謝感謝!