Dagger2的入坑指南[捂臉][詳]!!
前言
dagger2的文章從寥寥可數到現在的數不勝數,可見其熱門程度。
這篇文章主要是記錄我對dagger2的理解,從基本使用,到實際運用,由淺入深。以及dagger2的一些變化。
希望大家能取其精華,去其糟粕,謝謝。
目錄結構
為什麼要使用dagger2?
我想這是許多人的困惑。為什麼不直接new一個物件。 而是通過配置各式各樣的註解達到new的目的?看了許許多多的文章,都指向一個觀點,一切是為了解耦。
從需求的角度
比如業務類UserService(UserApi api) . 需要構造這個函式。一開始例項化簡單,但是隨著業務的跟進你需要儲存一些使用者設定,建構函式加入SharedPreferences。
隨著建構函式的數量不斷增加,就會變得越來越累贅,並且又是多人合作,依賴別人寫的物件。改起來你說麻煩不(TVT).這就是為什麼dagger2適合大型的專案
如果是小型專案,而且程式碼都是自己擼的。對於生命週期和使用的物件的依賴關係又比較熟悉,這時可以考慮不使用。當然如果業務類建構函式複雜且需要注入的物件多,不妨可以考慮考慮。
總的來說!對面這樣的情況Dagger2維護起來就方便多了,可以使用一個moudule來維護。可以理解為倉庫吧。總之就是維護多個倉庫。裡面提供所需要的實體物件。
直接在宣告的時候
@Inject
UserService mUserService;
這時無論UserService 需要依賴多少物件.都ok.會自動去倉庫去尋找自己所需要的構造物件。從而達到解耦的目的。
從開發者的角度
說實話,落後就要捱打。
基本的使用
依賴
compile 'com.google.dagger:dagger:2.12'
annotationProcessor 'com.google.dagger:dagger-compiler:2.12'
先來一個最簡單的需求。在activity例項化UserService業務類
通常做法:activity 直接new。
dagger2做法:最簡單的注入。需要配合 @inject 與 @Component 註解構成。
不逼逼w(゚Д゚)w。直接 上程式碼說明
1 業務類。對建構函式進行宣告標識,告訴Dagger。生成物件時可以使用這個構造方法。
public class UserService {
@Inject //(1)
UserService() {
}
//假設請求網路資料方法
public void request(){
}
}
2 還需要一個橋樑Component,和activity產生產生關係。
@Component
public interface MainComponent {
//說明要在那個activity注入
void inject(MainActivity mainActivity);
}
3.寫好之後進行重構生成注入程式碼。
重構完後會生成一個DaggerMainComponent,提供注入,名字生成的規則是DaggerXXComponent。
最後在activity使用
public class MainActivity extends AppCompatActivity {
@Inject//(2)要new那個。就inject那個。
UserService mUserService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//(3)注入
DaggerMainComponent.builder().build().inject(this);
Log.w(MainActivity.class.getSimpleName(),mUserService.toString());
mUserService.request();
}
}
說明一下這兩個註解的意思:
@inject
對建構函式進行宣告,Dagger可以構建該類的例項。//(1)
對欄位,也就是成員變數宣告,就是告訴dagger2 我需要這個例項物件。//(2)
@Component
- 可以理解為橋樑,就是將它們聯絡起來。
這樣就完成一個物件最簡單的注入。
當然在實際的專案當中不可能那麼簡單。如果UserServic需要一個Gson,需要一個Retrofit,一些第三方的物件時,而你需要 @inject宣告建構函式。去告訴dagger2要那個物件。在這些情況下是不可行,因為第三方類不能修改。
面對這種情況,就需要@Module註解和@Provides註解來描述依賴關係了。 去解決以上的問題了
需求改變:Userservic 需要一個Gson物件。
業務類的修改,假設UserService需要Gson物件
public class UserService {
Gson gson;
@Inject
public UserService(Gson gson) {
this.gson = gson;
}
public Gson getGson() {
return gson;
}
public void request() {
}
}
這時如果要例項化Gson,按照上面的步驟來說,應該在Gson的建構函式標識@inject。才可以被例項化,由於無法做到,所以就只能宣告Module倉庫來提供Gson物件。
宣告Module
@Module
public class UserModule {
@Provides
Gson provideGson() {
return new Gson();
}
// 如果有了module,可以把Userservic建構函式的@inject去掉.
//依賴物件由module提供。
// 如果沒有去掉Userservic的inject並且也在module提供了例項、那麼。
//記住,@Module級別高於@Inject。
/* @Provides
UserService providesUserService(Gson gson) {
return new UserService(gson);
}
*/
}
@Module
- 註解的類表明它可以提供依賴物件,宣告這是一個倉庫。標識可以提供物件
@Provides
- 告訴Dagger我們想要構造物件並提供這些依賴
按照慣例,@Provides方法以provide開頭,Module類以Module結尾。
修改Component,構建module的關係。
@Component(modules = UserModule.class)//可以有多個modules={xxxModule.class,XXclass,等等}
public interface MainComponent {
void inject(MainActivity mainActivity);
}
最後在重新編譯。在activity呼叫
DaggerMainComponent.builder().userModule(new UserModule()).build().inject(this);
Gson gson = mUserService.getGson();
Log.w(MainActivity.class.getSimpleName(), gson.getClass().toString());
有人會說如果Service需要的物件Context,module要怎麼提供?
Userservic
@Inject
public UserService(Gson gson, Context context) {
this.gson = gson;
this.context = context;
}
Module可以通過建構函式去提供例項,並提供出去。
Context mContext;
public UserModule(Context context) {
this.mContext = context;
}
@Provides
Context provideContext(){
return mContext;
}
最後編譯,activity呼叫。
DaggerMainComponent.builder().userModule(new UserModule(this)).build().inject(this);
3 基本使用總結
如果能看懂上面的東西。大概就算是入門了吧。嗯嗯,基本操作。
接下來我們就慢慢擴充我們的需求。慢慢融入到我們的真實專案。
循循漸進的專案搭建
先看一段程式碼:
UserModule:很簡單就提供一個Gson
@Module
public class UserModule {
@Provides
Gson provideGson() {
return new Gson();
}
}
Component
@Component(modules = UserModule.class)
public interface MainComponent {
void inject(MainActivity mainActivity);
}
activity:注入2個Gson.
@Inject
Gson mGson1;
@Inject
Gson mGson2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainComponent.builder().userModule(new UserModule()).build().inject(this);
Log.w("MainActivity", Integer.toHexString(mGson1.hashCode()));
Log.w("MainActivity", Integer.toHexString(mGson2.hashCode()));
}
可以看到這是兩個不同的物件
需求:
通常我們在專案中有物件需用頻率過高,需要保持全域性單例的情況,也就是達到複用的目的。例如全域性的Application
,全域性的OkHttpClient ,等等….。
通常做法:靜態變數,或者單例模式封裝,等…
Dagger2:使用@Singleton標識 保持單例,也可以使用自定義scope或者使用Reusable。先說說@Singleton
我們修改一下程式碼
module
@Provides
@Singleton
Gson provideGson() {
return new Gson();
}
Component
@Singleton
@Component(modules = UserModule.class)
public interface MainComponent {
void inject(MainActivity mainActivity);
}
activity 不改。看看結果
就是那麼簡單。
@Singleton
注意事項:
別想的太難,僅僅只標記而已,通過這個標記。dagger2獲取例項的方法會生成單例。具體的可以看看生成後的原始碼
module提供物件的方法用@Singleton註解宣告,其Component也要保持一致哦。不然會編譯不通過。
- 除了上面要module和Component要使用同一個之外。想要要保證物件的全域性單例,Component只能構建一次。比如:
A activity : Aactivity 注入 。
@inject
Gson gson;
DaggerMainComponent.builder().userModule(new UserModule()).build().inject(this);
B Activity Bactivity 注入 。
@inject
Gson gson;
DaggerMainComponent.builder().userModule(new UserModule()).build().inject(this);
其中A和B的Gson是不可能是同一個物件的,因為初始化的原因。所以要提供整個App的單例就必須保證初始化構建一次。
所有我們可以在自定義Application構建。
public class MyApplication extends Application {
private DaggerMainComponent daggerMainComponent;
@Override
public void onCreate() {
super.onCreate();
//構建
daggerMainComponent= DaggerMainComponent.builder().userModule(new UserModule()).build();
}
public DaggerMainComponent getDaggerMainComponent() {
return daggerMainComponent;
}
}
A activity 和 b activity 使用
MyApplication myApplication = (MyApplication) getApplication();
myApplication.getDaggerMainComponent().inject(this);
這樣就可以保持單例,從而達到複用的目的了
有了上面的的基礎,我們可以搭建屬於我們的第一個模組。
公共模組
讓dagger2提供App全域性所需要的物件
先搭建我們的公共倉庫。
AppModule :最基礎的,提供全域性的Application 各位看情況而定
@Module
public class AppModule {
Application mApplication;
public AppModule(Application application) {
mApplication = application;
}
@Provides
@Singleton
Application providesApplication() {
return mApplication;
}
@Provides
@Singleton
SharedPreferences providesSharedPreferences(Application application) {
return PreferenceManager.getDefaultSharedPreferences(application);
}
}
NetModule :公共網路請求,使用的是 retrofit2, 根據自己的情況搭建
@Module
public class NetModule {
String mBaseUrl;
// 構造module所需要的引數。根據每個人的情況而定
public NetModule(String baseUrl) {
this.mBaseUrl = baseUrl;
}
@Provides
@Singleton
Cache provideOkHttpCache(Application application) {
int cacheSize = 10 * 1024 * 1024; // 10 MiB
return new Cache(application.getCacheDir(), cacheSize);
}
@Provides
@Singleton
Gson provideGson() {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
return gsonBuilder.create();
}
@Provides
@Singleton
HttpLoggingInterceptor provideHttpLoggingInterceptor() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
return interceptor;
}
@Provides
@Singleton
OkHttpClient provideOkHttpClient(HttpLoggingInterceptor httpLoggingInterceptor,Cache cache) {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.cache(cache).
addInterceptor(httpLoggingInterceptor)
.connectTimeout(30, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.build();
return builder.build();
}
@Provides
@Singleton
Retrofit provideRetrofit(Gson gson, OkHttpClient mOkHttpClient) {
return new Retrofit.Builder()
.baseUrl(mBaseUrl)
.client(mOkHttpClient)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
}
基礎的module搭好後,關聯 Component
@Singleton
@Component(modules = {AppModule.class, NetModule.class})
public interface AppComponent {
void inject(MyApplication application);
}
最後一步,重新編譯。然後使用
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
DaggerAppComponent.builder()
.appModule(new AppModule(this))
.netModule(new NetModule("www.github.com"))
.build().inject(this);
}
}
這時候你可能會困惑,你在MyApplication注入用處不大 ,難道要在這裡進行網路請求麼?當然如果有需要例項化的物件也可以注入。
如果AMainActivity,BMainActivity 需要用到這些公共物件該怎麼做?
很簡單,在Component關聯上不就行了嗎?
@Singleton
@Component(modules = {AppModule.class, NetModule.class})
public interface AppComponent {
void inject(MyApplication application);
void inject(AMainActivity activity);
void inject(BMainActivity activity);
}
這樣做也行,如果按照上面的這樣做,你必須要在 A和B的activity去構建注入才可以獲取到這些物件,但是這些物件就不是單例的了。
就忘了最初的考慮。想要保證全域性單例,Component只能構建一次,
所以MyApplication 要提供出Component,並且保證構建一次。
修改如下
public class MyApplication extends Application {
private AppComponent mAppComponent;
@Override
public void onCreate() {
super.onCreate();
mAppComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.netModule(new NetModule("www.github.com"))
.build();
}
public AppComponent getAppComponent() {
return mAppComponent;
}
}
AMainActivity
@Inject
Retrofit mRetrofit;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((MyApplication)getApplication()).getAppComponent().inject(this);
Log.w("AMainActivity", mRetrofit.toString());
findViewById(R.id.tv_text2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(AMainActivity.this,BMainActivity.class));
}
});
}
BMainActivity
@Inject
Retrofit mRetrofit;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((MyApplication)getApplication()).getAppComponent().inject(this);
Log.w("BMainActivity", mRetrofit.toString());
//((MyApplication)getApplication()).getAppComponent().inject();
}
這樣就保證了
雖然這樣可以保證全域性的唯一性。但是隨著activity的增多,可能每個activity用到的module都不一樣,也就是需要注入的物件不同。
@Singleton
@Component(modules = {AppModule.class, NetModule.class,BModule.class,AModule.class,XModule.class,.....Module.class})
public interface AppComponent {
void inject(MyApplication application);
void inject(AMainActivity activity);
void inject(BMainActivity activity);
void inject(XMainActivity activity);
......
}
一個Component堆多了module看著也不舒服。就像整個專案沒有BaseActivity一樣.你覺得合理麼?
所以下面介紹一下Component dependencies ,和自定義Scope。
@Component dependencies
很簡單,直接看程式碼。
假設我們AMainActivity 需要Amodule 提供業務物件。各位根據實際情況而定
@Module
public class AModule {
@Provides
UserService providesUserService(){
return new UserService();
}
}
我們新建一個ActivityComponent 統籌所有的Activity.
@Component(modules = {AModule.class}, dependencies = AppComponent.class)//可以依賴多個Component
public interface ActivityComponent {
void inject(AMainActivity aMainActivity);
}
注意:
可以看到 我們的 Component 加上了dependencies 並且繼承與AppComponent。
這時候要注意了。如果現在進行編譯的話會編譯不通過。
這裡有個規則。
如果依賴的Component需要用到父Component的物件,必須要父Component通過方法提供出來。
所以, AppComponent 修改如下
@Singleton
@Component(modules = {AppModule.class, NetModule.class})
public interface AppComponent {
//暴露出子Component 需要的物件。各位根據直接的情況而定。
//gson
Gson gson();
Application application();
OkHttpClient okHttpClient();
SharedPreferences sharedPreferences();
Retrofit retrofit();
void inject(MyApplication application);
void inject(BMainActivity bMainActivity);
}
這時候在編譯就會出現以下問題。
大概的意思是沒有scope的不能依賴有scope的元件,也就是說你的Component要有一個Scope修飾
然後你在ActivityComponent 加上@Singleton標識還是上面那個提示。
這時候注意了。
@Component的dependencies與@Component自身的scope不能相同。
可以通過自定義Scope來解決上面的問題,這算是自定義Scope的場景使用之一。
自定義Scope
在看別人的專案的時候通常會看到兩個Scope,ActivityScope 跟 FragmentSopce。 (也有可能其他命名。隨意)
如其字義,好理解,使用於Activity和fragment。
廢話不多說,直接仿寫 @Singleton。
ActivityScope
@Scope
@Documented
@Retention(RUNTIME)
public @interface ActivityScope {}
FragmentScope 和上面的一樣,改個名字即可。
然後在我們的ActivityComponent修改如下
@ActivityScope
@Component(modules = {AModule.class}, dependencies = AppComponent.class)
public interface ActivityComponent {
void inject(AMainActivity aMainActivity);
}
當然,如果想依賴的Module也希望提供單例的話,這時也可以加上@ActivityScope即可
@Module
public class AModule {
@Provides
@ActivityScope
UserService providesUserService(){
return new UserService();
}
}
最後編譯即可。
AMainActivitty
//((MyApplication)getApplication()).getAppComponent().inject(this);
DaggerActivityComponent.builder().appComponent(((MyApplication)getApplication()).getAppComponent())
.build().inject(this);
如果是在fragment裡使用呢?和上面幾乎沒啥區別
@FragmentScope
@Component(modules = XXModule.class,....XXModule.class, dependencies = AppComponent.class)
public interface FragmentComponent {
void inject(XXFragment fragment);
// .....inject...
}
最後編譯使用即可。
也許上面所搭建方式的會與其他人的有所不同。
有些人是 一個模組 對應著一個Component和module。
在github上隨便找的專案截圖
activity
fragment
專案dagger2結構
這樣做也行,但是會寫比較多的 Component和module。
我就是懶一點。直接2個Component統籌全域性。當然,這不是重點。
重要的是怎麼理解這些知識點。正所謂萬變不離其宗。
專案的基本搭建就到此結束了。接下來是一些優化和其他相關注解。
專案搭建優化
Binding Instances 構建方式
我們可以看到上面搭建的module。如果需要特定的引數,有種方法是通過建構函式進行注入。
比如上面的NetModule
// 構造module所需要的引數。根據每個人的情況而定
public NetModule(String baseUrl) {
this.mBaseUrl = baseUrl;
}
也可以通過Component來提供,清晰。
我們就拿上面所寫的兩個module作為例子修改。優化
新建AppModule2
@Module
public class AppModule2 {
/*
由於要改為由Component提供引數,所以這裡註釋掉
Application mApplication;
public AppModule2(Application application) {
mApplication = application;
}
@Provides
@Singleton
Application providesApplication() {
return mApplication;
}*/
@Provides
@Singleton
SharedPreferences providesSharedPreferences(Application application) {
return PreferenceManager.getDefaultSharedPreferences(application);
}
}
NetModule2
@Module
public class NetModule2 {
/*
改為由Component提供!
String mBaseUrl;
// 構造module所需要的引數。根據每個人的情況而定
public NetModule2(String baseUrl) {
this.mBaseUrl = baseUrl;
}*/
//.. 省略
//把mBaseUrl 作為引數傳入
@Provides
@Singleton
Retrofit provideRetrofit(Gson gson, OkHttpClient mOkHttpClient,String mBaseUrl) {
return new Retrofit.Builder()
.baseUrl(mBaseUrl)
.client(mOkHttpClient)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
}
最後Component
@Singleton
@Component(modules = {AppModule2.class, NetModule2.class})
public interface AppComponent2 {
@Component.Builder
interface Builder {
// Module所需要的引數可以這樣提供
@BindsInstance
Builder application(Application application);
@BindsInstance
Builder baseUrl(String baseUrl);
AppComponent2 build();
}
//gson
Gson gson();
Application application();
OkHttpClient okHttpClient();
SharedPreferences sharedPreferences();
Retrofit retrofit();
void inject(MyApplication application);
void inject(BMainActivity bMainActivity);
}
使用
DaggerAppComponent2.builder().application(this).baseUrl("https://api.xxx.com/").build().inject(this);
Reusable Scope 作用域
在上面我們使用到了Singleton 和 自定義了 activityScope 和 fragmentScope。定義他們的原因可以複用物件,並且可以保證區域性單例。
假如你僅僅是需要快取依賴的例項,達到複用的效果。且不需要那麼多的scope約束。可以考慮用這個替換。
Reusable 作用域不關心繫結的 Component,只需要標記目標類或 provide 方法即可。
專案作用域優化,重新修改一下module
- 把module中Provides下面的Singleton替換為Reusable
- 刪除component上面的Scope
AppModule2
@Module
public class AppModule2 {
@Provides
@Reusable //替換原來Scope
SharedPreferences providesSharedPreferences(Application application) {
return PreferenceManager.getDefaultSharedPreferences(application);
}
}
NetModule2(略)
意思和上面一樣,替換即可。
Component 把Scope刪除即可
@Component(modules = {AppModule2.class, NetModule2.class})
public interface AppComponent2 {
@Component.Builder
interface Builder {
// Module所需要的引數可以這樣提供
@BindsInstance
Builder application(Application application);
@BindsInstance
Builder baseUrl(String baseUrl);
AppComponent2 build();
}
//gson
Gson gson();
Application application();
OkHttpClient okHttpClient();
SharedPreferences sharedPreferences();
Retrofit retrofit();
void inject(MyApplication application);
}
子Component,一樣Scope刪除即可,這裡的依賴module各位自己定。
@Component( dependencies = AppComponent2.class)
public interface ActivityComponent2 {
void inject(Di2Activity di2Activity);
void inject(Di2Activity2 di2Activity);
}
在MyApplication 提供ActivityComponent2例項。
private AppComponent2 mAppComponent2;
@Override
public void onCreate() {
super.onCreate();
mAppComponent2 = DaggerAppComponent2.builder().application(this).baseUrl("https://api.xxx.com/").build();
}
public AppComponent2 getAppComponent2() {
return mAppComponent2;
}
然後 使用測試列印
Di2Activity
@Inject
Retrofit mRetrofit;
MyApplication myApplication = (MyApplication) getApplication();
DaggerActivityComponent2.builder().appComponent2(myApplication.getAppComponent2()).build().inject(this);
Log.w("Di2Activity",mRetrofit.toString());
Di2Activity2
@Inject
Retrofit mRetrofit;
MyApplication myApplication = (MyApplication) getApplication();
DaggerActivityComponent2.builder().appComponent2(myApplication.getAppComponent2()).build().inject(this);
Log.w("Di2Activity2",mRetrofit.toString());
檢視結果
這樣就保證了物件的複用了
擴充套件庫dagger.adnroid
為什麼會出現這個擴充套件庫呢?英文好大的大兄弟可以去看官網的介紹Dagger.android。
不好的話 那隻能看我吹牛逼 簡單的翻譯了。
如果fagment 和activity 要用到物件就不得不使用Dagger依賴注入例項。
public class FrombulationActivity extends Activity {
@Inject Frombulator frombulator;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// DO THIS FIRST. Otherwise frombulator might be null!
((SomeApplicationBaseType) getContext().getApplicationContext())
.getApplicationComponent()
.newActivityComponentBuilder()
.activity(this)
.build()
.inject(this);
// ... now you can write the exciting code
}
}
如果每新建一個Activity 或者fragment 都要寫一次,誰都想吐.
還有專業的原因:是它打破了依賴注入的核心原則:一個類不應該知道如何實現依賴注入。
對我來說這個擴充套件庫就是解決這個問題的。就是要達到注入一次,其他地方就不用理。
新增擴充套件庫
compile 'com.google.dagger:dagger-android-support:2.12'
annotationProcessor 'com.google.dagger:dagger-android-processor:2.12'
我們拋棄上面所寫的 子Component(ActivityComponent2) 採用新的方式
新建ActivityBindingModule 管理所有的Activity
@Module
public interface ActivityBindingModule {
//Di2Activity3 需要的特定 module 可以在這裡新增
@ContributesAndroidInjector(modules = DiModule.class)
Di2Activity3 di3ActivityInjector();
@ContributesAndroidInjector
Di2Activity4 di4ActivityInjector();
//...省略
}
DiModule 提供一個業務類
@Module
public class DiModule {
@Provides
@Reusable
DouBanService provideUserservice(Retrofit r){
return new DouBanService(r);
}
}
public class DouBanService {
private Retrofit mRetrofit;
public DouBanService(Retrofit mRetrofit) {
this.mRetrofit = mRetrofit;
}
public void request() {
DouBanApi douBanApi = mRetrofit.create(DouBanApi.class);
douBanApi.getBook().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<Book>() {
@Override
public void accept(Book book) throws Exception {
Log.w("DouBanService", book.toString());
}
});
}
}
修改 component
@Component(modules = {
AppModule2.class,
NetModule2.class,
ActivityBindingModule.class,
AndroidSupportInjectionModule.class
})
public interface AppComponent2 extends AndroidInjector<MyApplication2> {
@Component.Builder
interface Builder {
// Module所需要的引數可以這樣提供
@BindsInstance
Builder application(Application application);
@BindsInstance
Builder baseUrl(String baseUrl);
AppComponent2 build();
}
//gson
Gson gson();
Application application();
OkHttpClient okHttpClient();
SharedPreferences sharedPreferences();
Retrofit retrofit();
void inject(MyApplication application);
}
MyApplication2
public class MyApplication2 extends Application implements HasActivityInjector {
@Inject
DispatchingAndroidInjector<Activity> dispatchingActivityInjector;
@Override
public void onCreate() {
super.onCreate();
DaggerAppComponent2.builder().baseUrl("https://api.douban.com/").application(this).build().inject(this);
}
@Override
public AndroidInjector<Activity> activityInjector() {
return dispatchingActivityInjector;
}
}
最後新建一個BaseActivity
public abstract class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
//統一注入,要在super之前。
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
setContentView(layout());
init();
}
protected abstract void init();
@LayoutRes
protected abstract int layout();
}
然後讓Activity繼承BaseActivity.直接使用即可
public class Di2Activity3 extends BaseActivity {
@Inject
Retrofit mRetrofit;
@Inject
DouBanService mDouBanService;
@Override
protected void init() {
Log.w("Di2Activity2",mRetrofit.toString());
findViewById(R.id.tv_text2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(Di2Activity3.this,Di2Activity4.class));
}
});
mDouBanService.request();
}
@Override
protected int layout() {
return R.layout.activity_main;
}
}
結果
fragment中怎麼使用 和 原始碼就不分析了。可以參考下,下面幾位大兄弟的文章
順便可以參考一下googlesamples中,dagger的使用實戰。
其他註解
@Qualifier和@Named
這兩個註解都是同一個意思。就是當你的module提供了同一個物件。然而在使用的時候dagger2不知道用那個。
限定符為依賴分別打上標記,指定提供某個依賴
@Named
@Module
public class UserModule {
@Provides
@Singleton
@Named("Book1")
Book provideBook1() {
Book book =
相關推薦
Dagger2的入坑指南[捂臉][詳]!!
前言
dagger2的文章從寥寥可數到現在的數不勝數,可見其熱門程度。
這篇文章主要是記錄我對dagger2的理解,從基本使用,到實際運用,由淺入深。以及dagger2的一些變化。
希望大家能取其精華,去其糟粕,謝謝。
目錄結構
Angular2入坑指南——管道(搜索功能)
意見 als brush derby 我會 不足 ng- 請求 script 想必大家做項目都會遇到搜索功能吧,通常都是搜索本地數據,如果通過http去請求後臺再回顯的話,那響應速度簡直叫人抓狂,所以大多數都是先存到本地然後進行搜索回顯。Angular1的方法很簡單,只需要
MegaCli入坑指南
megaraid megacli MegaCli 是LSI公司官方提供的SCSI卡管理工具,由於LSI被收購變成了現在的Broadcom,所以現在想下載MegaCli,需要去Broadcom官網查找Legacy產品支持,搜索MegaRAID即可。 現在官方有storcli,整合了LSI和3ware所有
YouCompleteMe入坑指南
YouCompleteMe vim glibc 本文記錄自己安裝YouCompleteMe(簡稱YCM)這款VIM插件的過程,主要目的是記錄出錯情況和解決方法。
YCM號稱史上最難裝vim插件,根據我的安裝經驗,此言不虛。得知其強大之時,我便不假思索開始安裝。
我所用的系統為CentOS6.8,幾
angular 1.5.X 防入坑指南
使用 註意 bsp -o lar option 入坑指南 col 5.x 1.ne-repeat使用註意事項
在設置<select>類控件“ng-repeat”屬性時,"as"前部分對應value值,用於選中時獲取,"as"後面部分對應元素的text值,用
RocketMq入坑指南
led apach 雲主機 strong conn caused 6.5 tex 本地
報錯信息Caused by: org.apache.rocketmq.remoting.exception.RemotingConnectException: connect to &
WEEX入坑指南(1)
http test 技術分享 inf 新建文件夾 創建 com img 目的 weex create newtest
然後在某個階段卡死,
解決方案:
在路徑下創建新建文件夾,並命名為項目的名稱。
WEEX入坑指南(1)
<<MYSQL必知必會>> 入坑指南
www. 百度 pan bsp 下載 問題 需要 方便 down 問題:
一開始找不到下載資源。
書中的MySQL Administrator 以及 MySQL Query Brower 已經不適合MYSQL最新版本。
MYSQL下載安裝
MYSQL新工
disconf原理 “入坑”指南
之前有了解過disconf,也知道它是基於zookeeper來做的,但是對於其執行原理不太瞭解,趁著週末,debug下原始碼,也算是不枉費週末大好時光哈 :) 。關於這篇文章,筆者主要是參考disconf原始碼和官方文件,若有不正確地方,感謝評論區指正交流~
disconf是一個分
K8S入坑指南 - 分散式叢集方案探討
前言
隨著團隊應用產品的不斷增多,伺服器運營人員的工作量做到,而且有許多重複工作和不必要的勞動力。 並且,為了滿足前後端,運維工作的完全分離,我們需要對運維工作進行很好的調整。 經過討論,一方面,運維工作文件化,另一方面加速推進自動化部署、監控、維護系統的建設與完善。 經過調研
Docker入坑指南之RUN
總有一些場景,我們需要自己製作一個映象,可以快速還原環境,又不想被其他因素干擾映象的純淨,這個時候,就可以選擇Docker了,啟動便捷,映象還原很快捷,除了上手不容易。
最近入坑研究了一番,小有心得,故寫一篇雜文,記錄自己的踩坑經歷。
安裝Docker的過程可以參考其他前輩的文章,不再贅述,從實戰角度說,
Docker入坑指南之EXEC
容器啟動之後,如果我們需要進入容器內修改配置,比如mysql修改啟動配置
我們啟動的附加引數是不是shell,這個時候就可以用docker exec了,docker除了對image引數以外,大部分命令,可以多docker容器ID操作的,也可以對docker容器別名一樣的使用
docker exec
WKWebView 入坑指南
WKWebView 入坑指南
因專案JS互動需要,同時因為支援的系統開始從iOS 8 之後,所以就打算使用WKWebView替換掉專案中的UIWebView。本篇文章會持續更新在使用過程總碰到的問題。
坑一:在使用測試環境時,因為有時後臺返回url並不規範,url不包含s
Flutter入坑指南:編寫第一個Flutter應用
本文由 愛學園平臺 進行聯合編輯整理輸出
原作者:愛學園——莫比烏斯環 這是 Flutter 系列文章的第二篇,關於 Flutter 的相關學習文章後面還有很多,如果您喜歡的話,請持續關注 ,謝謝!
Flutter 是 Google 推出的移動端跨平臺開發框架,使
Flutter入坑指南:開發環境搭建
本文由 愛學園平臺 進行聯合編輯整理輸出
原作者:愛學園——莫比烏斯環
雖說Flutter出現有一段時間了,但大家對它的瞭解卻不是很深,但直到2018谷歌開發者大會在上海的召開,它才真正進入開發者的世界。Flutter的出現為跨平臺開發開闢了新的方向,但是與之相應
C語言入坑指南-被遺忘的初始化
前言
什麼是初始化?為什麼要初始化?靜態變數和區域性變數的初始化又有什麼區別?實際應用中應該怎麼做?本文將一一回答這些問題。
什麼是初始化
初始化指的是對資料物件或者變數賦予初始值。例如:
int value = 8; //宣告整型變數並初始化為8int&nbs
Omi 入坑指南 The second floor 初步接觸
Omi 已經出了 5.0 版本,由於新手,我們還是使用官方提供的 Cli 去安裝,安裝完畢後你會發現還是Omi 4.0的那個版本
$: cnpm install -g omi-cli //安裝全域性 omi-cli
$: omi -v //打印出來的是 3.0.25 版本
複製程式碼
在Cli中提供了4中
Kotlin快速入坑指南(幹貨型文檔)
一個個 urn 應對 在線 都是 iter 返回 分類 指南 <p style="text-align:center;color:#42A5F5;font-size:2em;font-weight: bold;">前言
即使每天10點下班,其
給 Web 開發人員的以太坊入坑指南
以太坊現在各種學習資料數不勝數,但由於以太坊正處於飛速發展階段,有些學習資料很快就過時了。所以想找到有價值的資料無異於大海撈針。我費了很大功夫,才建立起對以太坊的整體認識,搞清楚它的工作機制。我相信很多躍躍欲試的開發人員正面臨著跟我一樣的問題,所以我把自己的認識整理出來,希望能對大家有
【vue 入坑指南 】vue 基礎語法
【vue 入坑指南 一 】vue 基礎語法
1.模板語法
1.1 Mustache語法
{{msg}} //在html獲取data中msg變數的值
1.2 Html賦值
v-html="" //將內容當成html標籤輸出 .html()類似
1.