Dagger2的组件依赖及使用详解

来源:互联网 发布:科目二约车软件 编辑:程序博客网 时间:2024/04/29 01:00

上一篇详细讲解了Dagger2的大部分使用及基础知识,不太了解的朋友可以去看看http://blog.csdn.net/lylodyf/article/details/52981910。这一篇讲讲组件依赖及具体的使用。

组件依赖

顾名思义当然就是组件之间的依赖,即Component之间的依赖,不知是否发现Component有个属性是dependencies,用以指定依赖的Component。那么组件依赖有什么用处呢?想象这样一个场景,有一个MainModule里面的实例化方法需要一个参数假设为Context,现在无法获得这个Context,但是在另一个组件AppComponent里面有,现在我们只需要让管理MainModule的MainComponent组件依赖APPComponent就可以轻松实现。也就是说组件依赖可以让子组件获得父组件暴露出来的对象。

使用组件依赖有几点需要注意:

1.两个依赖的组件不能共享作用域,什么意思,也就是他们指定的作用域一定要不同

2.父组件必须暴露出子组件所需要的对象


下面通过一个具体实例来说明,其中包含了Dagger2的具体使用实践。

目录结构


AppComponent

@Singleton@Component(modules = AppModule.class)public interface AppComponent {    //Exposed to sub-graphs.    Context context();    ToastUtil toastUtil();    SharedPreferences sharedPreferences();}
可以看到这里面有三个方法,之前不是说过实现组件依赖父组件必须暴露出方法吗,这里就是向子组件暴露了三个方法。


AppModule

@Modulepublic 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

@Modulepublic 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

看看打印出来的日志



发现全部都不是空的,并且显示出了Toast。但是记得我们只在MainModule中提供了User的实例化方法吗,然后SharedPreference和ToastUtil也不为空,这自然就是因为依赖的APPComponent的原因。

对了这个TestClass有是什么东东,好像在其他地方都没有使用出现过,为什么打印出来又不为空呢

TestClass

@UserScopepublic class TestClass {    @Inject    public TestClass() {    }}
很简单的一个自定义类,只是制定了和MainComponent一样的作用域和在构造函数上面添加了@Inject,这样就可以直接使用了。


至此完毕,所以,你学会了吗


源码地址




0 0
原创粉丝点击