天天看點

Dagger2的元件依賴及使用詳解

上一篇詳細講解了Dagger2的大部分使用及基礎知識,不太了解的朋友可以去看看http://blog.csdn.net/lylodyf/article/details/52981910。這一篇講講元件依賴及具體的使用。

元件依賴

顧名思義當然就是元件之間的依賴,即Component之間的依賴,不知是否發現Component有個屬性是dependencies,用以指定依賴的Component。那麼元件依賴有什麼用處呢?想象這樣一個場景,有一個MainModule裡面的執行個體化方法需要一個參數假設為Context,現在無法獲得這個Context,但是在另一個元件AppComponent裡面有,現在我們隻需要讓管理MainModule的MainComponent元件依賴APPComponent就可以輕松實作。也就是說元件依賴可以讓子元件獲得父元件暴露出來的對象。

使用元件依賴有幾點需要注意:

1.兩個依賴的元件不能共享作用域,什麼意思,也就是他們指定的作用域一定要不同

2.父元件必須暴露出子元件所需要的對象

下面通過一個具體執行個體來說明,其中包含了Dagger2的具體使用實踐。

目錄結構

Dagger2的元件依賴及使用詳解
Dagger2的元件依賴及使用詳解

AppComponent

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {

    //Exposed to sub-graphs.
    Context context();

    ToastUtil toastUtil();

    SharedPreferences sharedPreferences();

}
           

可以看到這裡面有三個方法,之前不是說過實作元件依賴父元件必須暴露出方法嗎,這裡就是向子元件暴露了三個方法。

AppModule

@Module
public class AppModule {
    private MyApplication application;

    public AppModule(MyApplication application) {
        this.application = application;
    }

    @Provides
    @Singleton
    Context provideContext() {
        return application;
    }

    @Singleton
    @Provides
    ToastUtil provideToastUtil(Context context) {
        return new ToastUtil(context);
    }

    @Singleton
    @Provides
    SharedPreferences provideSP(Context context) {
        return context.getSharedPreferences("config", Context.MODE_PRIVATE);
    }
}
           

這裡面有三個執行個體化的方法,方法上面的Scope必須要和對應的Component的Scope一緻。也許有人會問其中有兩個方法傳入的參數Context是從哪裡來的,這是由于這裡面還有一個方法provideContext(),傳回的正是需要的Context。是以如果在這裡還有一個方法需要參數ToastUtil,這裡也有傳回ToastUtil的方法,也可以提供。

MainComponent

@UserScope
@Component(modules = MainModule.class, dependencies = AppComponent.class)
public interface MainComponent {

    void inject(MainActivity activity);
           

這裡指定了依賴AppComponent,有一個注射到MainActivity得方法,很好了解吧。至于@UserScope是一個自定義的Scope,不了解的可以去看看我上篇部落格。之前也說到和依賴的父元件的Scope必須不同,是以不能使用@Singleton

MainModule

@Module
public class MainModule {


    @Named("a")
    @UserScope
    @Provides
    User provideUser1(Child child) {
        return new User(child);
    }

    @Named("b")
    @UserScope
    @Provides
    User provideUser2(Child child) {
        return new User(child);
    }

}
           

隻有兩個傳回User的執行個體化方法,@Named是限定符,不了解的也可以去看看上篇部落格。User和Child就是兩個普通的類,這裡發現傳入的參數是Child,那麼有人又有疑問了,這裡并沒有傳回Child的方法啊,這個Child又是從哪裡來呢?下面我們先看看User類和Child類

User

public class User {

    public User(Child child) {
        Log.i("lzy", "調用User類無參構造方法");
    }
}
           

Child

public class Child {

    @Inject
    public Child() {
        Log.i("lzy", "調用Child類的無參構造方法");
    }

}
           

可以看到User并沒有什麼特别,隻是構造函數需要傳入一個Child。但是看看Child,構造函數上面加了@Inject注解,上一篇部落格我們不是講過提供構造方法有兩種方式嗎,先到Module中找,沒有找到會找有@Inject的構造函數。是以上面的Child就是從這裡來的。

MyApplication

public class MyApplication extends Application {

    private AppComponent appComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        appComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build();
    }

    public AppComponent getAppComponent() {
        return appComponent;
    }

}
           

在Application中執行個體化了APPComponent,并且向外提供一個擷取它的方法。當然要記得在manifest檔案中配置。

MainActivity

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "lzy";

    @Named("a")
    @Inject
    User user;

    @Inject
    SharedPreferences sp;

    @Inject
    ToastUtil toastUtil;

    @Inject
    TestClass test;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        DaggerMainComponent.builder().appComponent(getAppComponent()).mainModule(new MainModule())
                .build().inject(this);


        Log.i(TAG, "User: " + user);
        Log.i(TAG, "SharedPreference: " + sp);
        Log.i(TAG, "test: " + test);
        toastUtil.showToast("呵呵哈哈哈");

    }

    private AppComponent getAppComponent() {
        return ((MyApplication) getApplication()).getAppComponent();
    }
}
           

在這裡調用了 DaggerMainComponent.builder().appComponent(getAppComponent()).mainModule(new MainModule()).build().inject(this)把MainActivity注入到MainComponent裡面,并且聲明了四個對象,User、SharedPreference、ToastUtil和TestClass

看看列印出來的日志

Dagger2的元件依賴及使用詳解
Dagger2的元件依賴及使用詳解

發現全部都不是空的,并且顯示出了Toast。但是記得我們隻在MainModule中提供了User的執行個體化方法嗎,然後SharedPreference和ToastUtil也不為空,這自然就是因為依賴的APPComponent的原因。

對了這個TestClass有是什麼東東,好像在其他地方都沒有使用出現過,為什麼列印出來又不為空呢

TestClass

@UserScope
public class TestClass {

    @Inject
    public TestClass() {
    }

}
           

很簡單的一個自定義類,隻是制定了和MainComponent一樣的作用域和在構造函數上面添加了@Inject,這樣就可以直接使用了。

至此完畢,是以,你學會了嗎

源碼位址

繼續閱讀