Dagger2进阶使用

2017-02-15  本文已影响0人  notrynobug

1 知识回顾

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

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 也是不一样
上一篇下一篇

猜你喜欢

热点阅读