1. 程式人生 > >Dagger2的入坑指南[捂臉][詳]!!

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

  1. 對建構函式進行宣告,Dagger可以構建該類的例項。//(1)

  2. 對欄位,也就是成員變數宣告,就是告訴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 和 自定義了 activityScopefragmentScope。定義他們的原因可以複用物件,並且可以保證區域性單例。

 假如你僅僅是需要快取依賴的例項,達到複用的效果。且不需要那麼多的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.