Dagger2进阶使用

1 知识回顾

先来回顾之前将的四个注解

  • @Inject:
    通常在需要依赖的地方使用这个注解。换句话说,你用它告诉Dagger这个类或者字段需要依赖注入。这样,Dagger就会构造一个这个类的实例并满足他们的依赖。
  • @Module:
    Modules类里面的方法专门提供依赖,所以我们定义一个类,用@Module注解,这样Dagger在构造类的实例时候,就知道从哪里去找到需要的依赖。
  • @Provide:
    在Modules中,我们定义的方法用这个注解,以此来告诉Dagger我们想要构造对象并提供这些依赖。
  • @Component
    Components从根本上来说就是一个注入器,也可以说是@Inject和@Module的桥梁,它的主要作用就是连接这两个部分。Components可以提供所有定义了的类型的实例。

2 模块化

就好比平时我们都需要对Http请求进行封装,在Dagger里呢,我们就要对Http进行模块化。 这里就举个例子,我们使用Retrofit网络请求框架,去请求天气Json数据。

我们先去写一个HttpModule

//HttpModule.java
@Module
public class HttpModule {
    @Singleton
    @Provides
    public OkHttpClient getOkHttpClient() {
        Log.i("http", "getOkHttpClient");
        return new OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS).readTimeout(10, TimeUnit.SECONDS).build();
    }
    @Provides
    @Singleton
    public Retrofit getRetrofit(OkHttpClient okHttpClient) {
        Log.i("http", "getRetrofit");
        return new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create()).baseUrl("http://www.weather.com.cn/data/sk/").client(okHttpClient).          addCallAdapterFactory(RxJavaCallAdapterFactory.create()).build();
    }
}
//HttpApi.java
public interface HttpApi {
    //http://www.weather.com.cn/data/sk/101010100.html
    @GET("101010100.html")
    Call<WeatherBean> getweather();
}

有人肯定会问 @Singleton是什么意思,这个注释表示单例使用的意思。为什么我们要进行实例化呢?因为我们每次网络请求都要对OkHttpClient和Retrofit进行实例化,这样会造成资源的浪费,可以使单例模式下这是问程序的一种优化吧。 @Singleton的使用后面会讲。
接着我们来看看Component的代码

@Singleton
@Component(modules = HttpModule.class)
public interface ApplicationComponent {
    void inject(MainActivity mainActivity);
}

再来看看MainActivity中使用Dagger2

public class MainActivity extends AppCompatActivity {
    String TAG = "MainActivity";
    TextView textView;
    @Inject
    Retrofit retrofit;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView) findViewById(R.id.tv);
        DaggerApplicationComponent.create().inject(this);
        retrofit.create(HttpApi.class).getweather().enqueue(new Callback<WeatherBean>() {
            @Override
            public void onResponse(Call<WeatherBean> call, Response<WeatherBean> response) {
                Log.i("http", response.isSuccessful() + "" + response.body().getWeatherinfo().getCity());
                textView.setText(response.body().getWeatherinfo().getCity());
            }
            @Override
            public void onFailure(Call<WeatherBean> call, Throwable t) {
            }
        });
    }
}

3 Singleton 单例讲解

现在我们来讲解一下@Singleton 注解的使用的注意事项。

  1. module 的 provide 方法使用了 Singleton ,那么 component 就必须使用同一个注解
  2. Singleton 的生命周期依附于component,同一个module provide singleton ,不同component 也是不一样

第一点也就是为什么我要在ApplicationComponent中去使用Singleton注解
第二点大家可以自行去尝试。

4 升级用法

但是会有一个问题,如果我按照上面的这种方法去使用Http请求,还用上了单例模式,然而却体现不出单例模式的好处,按照上面的做法,我每个Activity使用 @Inject Retrofit retrofit;这个注解相对应的,我要对每个Activity创建对应的comoponent,这和单例有什么关系呢?
所以我们要在上述代码上进行修改,进行改进。我们需要将HttpModule 使用的对象提高一个档次,不是面向Activity这个级别而是面向Application这个级别。Application和Activity显然不是一个级别,通过Application再结合单例模式,这才是HttpModule真正使用的用处。
为此我们先来修改ApplicationComponent

@Singleton
@Component(modules = HttpModule.class)
public interface ApplicationComponent {
}

看到这个大家可能会有疑问,为什么不是像上面那样
void inject(Application application);?
因为如果我们要使用 void inject(MainActivity mainActivity)的话,表示Component将该module和MainActivity 连接,若要和Application连接不需要写。
然后我们就需要在Application中声明。

public class Application extends android.app.Application {
    @Override
    public void onCreate() {
        super.onCreate();
         DaggerApplicationComponent.create();
    }
}

这样就完成将Httpmodule和Application连接。
接下来我们还需要写一个Module类去返回HttpApi

@Module
public class ApiModule {
    @Provides
    HttpApi provideHttpapi(Retrofit retrofit) {
        return retrofit.create(HttpApi.class);
    }
}

但是Retrofit 这个对象在HttpModule中有返回,可是HttpModule已经和Application有连接了和ApiModule 没有任何关系。但是没关系,我们可以通过component去依赖(换句话说去继承可能会更好理解)

@Component(modules = ApiModule.class, dependencies = ApplicationComponent.class)
public interface HttpCompotent {
    void getactivity(MainActivity mainActivity);
}

然后在ApplicationComponent中加入一句话

@Singleton
@Component(modules = HttpModule.class)
public interface ApplicationComponent {
    Retrofit retrofit();
}

添加这句话的目的是为了然会返回Retrofit ,以至于让ApiModule 的provideHttpapi方法能过找到Retrofit 。
这个时候我们 Rebuild Project一下,很好报错了,这是为什么呢?下面我再告诉你们一些注意事项

  1. 没有@scope的component不能依赖有@scope的component
  2. component的dependencies与component自身的@scope不能相同,即组件之间的@scope不同

对于突然看到@scope一定很眼生,@scope就是作用域的意思@Singleton是里面的一种。


参照上面两点注意事项我们来修改HttpCompotent

@Applicaton_Annotation
@Component(modules = ApiModule.class, dependencies = ApplicationComponent.class)
public interface HttpCompotent {
    void getactivity(MainActivity mainActivity);
}

//Applicaton_Annotation .java
@Scope
@Documented
@Retention(RUNTIME)
public @interface Applicaton_Annotation {
}

因为ApplicationComponent有依赖@scope也就是@Singleton,使用HttpCompotent 也需要依赖@scope,但又不能和ApplicationComponent一样,使用我们就参照@Singleton的格式复制了一份名叫@Applicaton_Annotation。
这样Rebuild Project就不会报错了,说明Dagger注入成功。接下来我们来使用Dagger

public class MainActivity extends AppCompatActivity {
    String TAG = "MainActivity";
    TextView textView;
    @Inject
    HttpApi httpApi;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView) findViewById(R.id.tv);
        DaggerHttpCompotent.builder()
                .applicationComponent(((Application) getApplication()).getApplicationComponent()).build().getactivity(this);
//因为HttpCompotent依赖了ApplicationCompotent,所以需要传入ApplicationCompotent对象,我们需要在Application里创建一个ApplicationCompotent对象
        httpApi.getweather().enqueue(new Callback<WeatherBean>() {
            @Override
            public void onResponse(Call<WeatherBean> call, Response<WeatherBean> response) {
                Log.i("http", response.isSuccessful() + "" + response.body().getWeatherinfo().getCity());
                textView.setText(response.body().getWeatherinfo().getCity());
            }

            @Override
            public void onFailure(Call<WeatherBean> call, Throwable t) {
            }
        });
    }
}

//Application .java
public class Application extends android.app.Application {
    ApplicationComponent applicationComponent;

    public ApplicationComponent getApplicationComponent() {
        return applicationComponent;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        applicationComponent=   DaggerApplicationComponent.create();
    }
}

这样我们就完成了Dagger的更高级的用法,就是对Retrofit的单例使用,可以避免重复的实例Retrofit。
最后我们来总结一下Dagger的使用注意事项

  1. componet 的 inject 方法接收父类型参数,而调用时传入的是子类型对象则无法注入
  2. component关联的modules中不能有重复的provide
  3. module 的 provide 方法使用了 scope ,那么 component 就必须使用同一个注解
  4. module 的 provide 方法没有使用 scope ,那么 component 和 module 是否加注解都无关紧要,可以通过编译
  5. component的dependencies与component自身的scope不能相同,即组件之间的scope不同
  6. 没有scope的component不能依赖有scope的component
  7. @Singleton 的生命周期依附于component,同一个module provide singleton ,不同component 也是不一样
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353

推荐阅读更多精彩内容