Dagger2的组件依赖及使用详解

前端之家收集整理的这篇文章主要介绍了Dagger2的组件依赖及使用详解前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

上一篇详细讲解了Dagger2的大部分使用及基础知识,不太了解的朋友可以去看看http://www.jb51.cc/article/p-yuztquvj-wr.html。这一篇讲讲组件依赖及具体的使用。

组件依赖

顾名思义当然就是组件之间的依赖,即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

@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

看看打印出来的日志



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

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

TestClass

@UserScope
public class TestClass {

    @Inject
    public TestClass() {
    }

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


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


源码地址

猜你在找的设计模式相关文章