Dagger2使用进阶

上一篇介绍了Dagger2简单的使用,这次我们接着介绍稍微复杂一点的使用场景。

module的provide方法带参数

首先我需要注入一个书名,代码如下:

public class MainActivity extends AppCompatActivity {

    @Inject
    String bookName;
}

然后我们接着编写module的代码

@Module
public class ActivityModule {
    @Provides
    String provideName(BookBean book){
        return book.getTitle();
    }

    @Provides
    BookBean provideBook(){
        BookBean bookBean = new BookBean();
        bookBean.setTitle("c++从入门到放弃");
        return bookBean;
    }

    @Provides
    PeopleBean providePeople(){
        People peopleBean = new PeopleBean();
        peopleBean.setTitle("mike");
        return peopleBean;
    }
}

我们可以看到provideName(BookBean book)方法是需要有一个BookBean的参数,当我们需要注入书名时,是通过传入的BookBean获取的。那这个BookBean怎么来的呢?大家可能已经注意到了下面还有一个provideBook()方法的返回类型是BookBean。没错,Dagger会自动寻找返回值为BookBean的方法,并将其返回的参数传入到provideName(BookBean book)方法中。这就是为什么不是调用providePeople()方法了,因为返回值不匹配。但是必须有一个条件,就是provideBook()必须被@Provides注解

@Qualifier注解

说到这里,那么问题来了,如果我的两个方法返回值一样的情况下怎么办呢?看代码:

@Module
public class ActivityModule {
    @Provides
    String provideName(BookBean book){
        return book.getTitle();
    }

    @Provides
    BookBean provideBook(){
        BookBean bookBean = new BookBean();
        bookBean.setTitle("c++从入门到放弃");
        return bookBean;
    }

    @Provides
    BookBean provideBook2(){
        BookBean bookBean = new BookBean();
        bookBean.setTitle("android从入门到放弃");
        return bookBean;
    }
}

这里就要介绍一个新的注解了@Qualifier。
首先我们先自定义两个注解,并用@Qualifier修饰

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface Android {
}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface Cpp {
}

然后修改module代码

    @Provides
    @Singleton
    @Cpp
    BookBean provideBook() {
        BookBean bookBean = new BookBean();
        bookBean.setTitle("c++从入门到放弃");
        return bookBean;
    }

    @Provides
    @Singleton
    @Android
    BookBean provideBook2() {
        BookBean bookBean = new BookBean();
        bookBean.setTitle("Android从入门到放弃");
        return bookBean;
    }

可以看到,只是添加了刚才自定义的注解。这就相当于给他们取了一个别名。
最后修改module的provideName

  @Provides
    String provideName(@Android BookBean book){
        return book.getTitle();
    }

注意看,参数前面增加了一个@Android注解。
至此,@Qualifier的用法就介绍完了。值得注意的是接下来讲的Component依赖有一点不同,会在下文介绍。


Component添加依赖

Component依赖就是指一个Component依赖另一个,有点类似于java的继承。
首先,我们先来写要被依赖的Component
这个例子里,我们模拟网络请求。所以需要依赖注入一个Retrofit,同时要使注入的Retrofit的生命周期和app保持一致,还好是一个单例。这时候我们要使用到两个新的注解@Singleton、@Scope。
先看MainActivity的代码

public class MainActivity extends AppCompatActivity {
    @Inject
    Retrofit retrofit;

    @Inject
    String bookName;

    ...
}

这里我们就是向服务器请求数据并打印出来。还有就是把注入的书名显示在textview上,这个主要作用后面再说。
接下来看被依赖的Component和Module的代码:

@Module
public class AppModule {
    private Retrofit retrofit;

    @Provides
    @Singleton
    OkHttpClient provideOkHttpClient() {
        return new OkHttpClient.Builder().build();
    }

    @Provides
    @Singleton
    Retrofit provideRetrofit(OkHttpClient okHttpClient) {
        return retrofit = new Retrofit.Builder()
                .client(okHttpClient)
                .baseUrl("http://api.douban.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();
    }

    // 演示@Qualifier在Component依赖时的使用
    @Provides
    @Singleton
    @Cpp
    BookBean provideBook() {
        BookBean bookBean = new BookBean();
        bookBean.setTitle("c++从入门到放弃");
        return bookBean;
    }

    @Provides
    @Singleton
    @Android
    BookBean provideBook2() {
        BookBean bookBean = new BookBean();
        bookBean.setTitle("Android从入门到放弃");
        return bookBean;
    }

}
@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
    OkHttpClient getClient();
    Retrofit getRetrofit();
    @Android
    BookBean getBook();
}

module中有三个参数的生成,都是单例。然后在Component中提供方法将module中的生成暴露给子图(这正是Dagger中 components工作的重要性质:如果你不想把modules的类型暴露出来,那么你就只能显示地使用它们。在这个例子中,我把这些元素暴露给子图, 如果你把他们删掉,编译的时候就会报错。这里不理解就先记着要这么写就行了)。
(BookBean getBook();被@Android修饰了,这就是前面提到的有所不同的就是如果你给方法取了别名,这里暴露的方法也需要被相同的注解修饰。)

然后来写真正的Component:

@ActivityScope
@Component(modules = ActivityModule.class, dependencies = AppComponent.class)
public interface ActivityComponent {
    void inject(MainActivity mainActivity);
}

这里多了一个@ActivityScope注解,这是一个我自定义的注解,看代码:

@Scope
public @interface ActivityScope {
}

它的作用是为了注入的Retrofit和app的生命周期保持一致,与Component的依赖无关。(至于@Scope我也没理解)
这里看到多加了一条dependencies = AppComponent.class,这就是将需要依赖的Component添加进去。
module的代码:

@Module
public class ActivityModule {
    @Provides
    String provideName(@Android BookBean book){
        return book.getTitle();
    }
}

然后module就没什么变化了,但是这里我加了provideName(BookBean book)方法。这是给MainActivity中的String bookName生成注入。而provideName(BookBean book)中的BookBean则来自AppModule中的BookBean provideBook()方法返回的值。也就是说带参的provide方法不一定要在同一个module中,也可以在被依赖的module中。
最后,在MainActivity中使用

public class MainActivity extends AppCompatActivity {
    @Inject
    Retrofit retrofit;

    @Inject
    String bookName;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        inject();
        Github github = retrofit.create(Github.class);
        github.htmls("1220562")
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<BookBean>() {
                    @Override
                    public void call(BookBean bookBean) {
                        System.out.println(bookBean);
                    }
                });
        TextView tv = (TextView) findViewById(R.id.textview);
        tv.setText(bookName);
    }

    private void inject() {
        DaggerActivityComponent.builder()
                .appComponent(DaggerAppComponent.create())
                .activityModule(new ActivityModule())
                .build().inject(this);
    }
}

主要看inject()方法的代码,可以看到我们先生成了一个DaggerActivityComponent.builder()然后调用了appComponent()方法,此时传入的就是要依赖的Component,这里就是DaggerAppComponent.create(),其他的就和以前一样了。

参考文章:http://www.jianshu.com/p/05ad9ad8a3e8
https://dreamerhome.github.io/2016/07/11/dagger%20for%20code/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值