1 知識(shí)回顧
先來回顧之前將的四個(gè)注解
- @Inject:
通常在需要依賴的地方使用這個(gè)注解途乃。換句話說,你用它告訴Dagger這個(gè)類或者字段需要依賴注入。這樣,Dagger就會(huì)構(gòu)造一個(gè)這個(gè)類的實(shí)例并滿足他們的依賴。 - @Module:
Modules類里面的方法專門提供依賴,所以我們定義一個(gè)類,用@Module注解,這樣Dagger在構(gòu)造類的實(shí)例時(shí)候侦鹏,就知道從哪里去找到需要的依賴。 - @Provide:
在Modules中臀叙,我們定義的方法用這個(gè)注解略水,以此來告訴Dagger我們想要構(gòu)造對(duì)象并提供這些依賴。 - @Component
Components從根本上來說就是一個(gè)注入器匹耕,也可以說是@Inject和@Module的橋梁聚请,它的主要作用就是連接這兩個(gè)部分。Components可以提供所有定義了的類型的實(shí)例稳其。
2 模塊化
就好比平時(shí)我們都需要對(duì)Http請(qǐng)求進(jìn)行封裝驶赏,在Dagger里呢,我們就要對(duì)Http進(jìn)行模塊化既鞠。 這里就舉個(gè)例子煤傍,我們使用Retrofit網(wǎng)絡(luò)請(qǐng)求框架,去請(qǐng)求天氣Json數(shù)據(jù)嘱蛋。
我們先去寫一個(gè)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();
}
有人肯定會(huì)問 @Singleton是什么意思蚯姆,這個(gè)注釋表示單例使用的意思。為什么我們要進(jìn)行實(shí)例化呢洒敏?因?yàn)槲覀兠看尉W(wǎng)絡(luò)請(qǐng)求都要對(duì)OkHttpClient和Retrofit進(jìn)行實(shí)例化龄恋,這樣會(huì)造成資源的浪費(fèi),可以使單例模式下這是問程序的一種優(yōu)化吧凶伙。 @Singleton的使用后面會(huì)講郭毕。
接著我們來看看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 單例講解
現(xiàn)在我們來講解一下@Singleton 注解的使用的注意事項(xiàng)。
- module 的 provide 方法使用了 Singleton 函荣,那么 component 就必須使用同一個(gè)注解
- Singleton 的生命周期依附于component显押,同一個(gè)module provide singleton ,不同component 也是不一樣
第一點(diǎn)也就是為什么我要在ApplicationComponent中去使用Singleton注解
第二點(diǎn)大家可以自行去嘗試。
4 升級(jí)用法
但是會(huì)有一個(gè)問題傻挂,如果我按照上面的這種方法去使用Http請(qǐng)求乘碑,還用上了單例模式,然而卻體現(xiàn)不出單例模式的好處金拒,按照上面的做法兽肤,我每個(gè)Activity使用 @Inject Retrofit retrofit;這個(gè)注解相對(duì)應(yīng)的,我要對(duì)每個(gè)Activity創(chuàng)建對(duì)應(yīng)的comoponent,這和單例有什么關(guān)系呢轿衔?
所以我們要在上述代碼上進(jìn)行修改沉迹,進(jìn)行改進(jìn)。我們需要將HttpModule 使用的對(duì)象提高一個(gè)檔次害驹,不是面向Activity這個(gè)級(jí)別而是面向Application這個(gè)級(jí)別。Application和Activity顯然不是一個(gè)級(jí)別蛤育,通過Application再結(jié)合單例模式宛官,這才是HttpModule真正使用的用處。
為此我們先來修改ApplicationComponent
@Singleton
@Component(modules = HttpModule.class)
public interface ApplicationComponent {
}
看到這個(gè)大家可能會(huì)有疑問瓦糕,為什么不是像上面那樣
void inject(Application application);
?
因?yàn)槿绻覀円褂?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連接。
接下來我們還需要寫一個(gè)Module類去返回HttpApi
@Module
public class ApiModule {
@Provides
HttpApi provideHttpapi(Retrofit retrofit) {
return retrofit.create(HttpApi.class);
}
}
但是Retrofit 這個(gè)對(duì)象在HttpModule中有返回圣勒,可是HttpModule已經(jīng)和Application有連接了和ApiModule 沒有任何關(guān)系费变。但是沒關(guān)系,我們可以通過component去依賴(換句話說去繼承可能會(huì)更好理解)
@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();
}
添加這句話的目的是為了然會(huì)返回Retrofit 圣贸,以至于讓ApiModule 的provideHttpapi方法能過找到Retrofit 挚歧。
這個(gè)時(shí)候我們 Rebuild Project一下,很好報(bào)錯(cuò)了吁峻,這是為什么呢滑负?下面我再告訴你們一些注意事項(xiàng)
- 沒有@scope的component不能依賴有@scope的component
- component的dependencies與component自身的@scope不能相同,即組件之間的@scope不同
對(duì)于突然看到@scope一定很眼生用含,@scope就是作用域的意思@Singleton是里面的一種矮慕。
參照上面兩點(diǎn)注意事項(xiàng)我們來修改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 {
}
因?yàn)锳pplicationComponent有依賴@scope也就是@Singleton,使用HttpCompotent 也需要依賴@scope啄骇,但又不能和ApplicationComponent一樣痴鳄,使用我們就參照@Singleton的格式復(fù)制了一份名叫@Applicaton_Annotation。
這樣Rebuild Project就不會(huì)報(bào)錯(cuò)了肠缔,說明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);
//因?yàn)镠ttpCompotent依賴了ApplicationCompotent,所以需要傳入ApplicationCompotent對(duì)象明未,我們需要在Application里創(chuàng)建一個(gè)ApplicationCompotent對(duì)象
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的更高級(jí)的用法槽华,就是對(duì)Retrofit的單例使用,可以避免重復(fù)的實(shí)例Retrofit趟妥。
最后我們來總結(jié)一下Dagger的使用注意事項(xiàng)
- componet 的 inject 方法接收父類型參數(shù)猫态,而調(diào)用時(shí)傳入的是子類型對(duì)象則無法注入
- component關(guān)聯(lián)的modules中不能有重復(fù)的provide
- module 的 provide 方法使用了 scope ,那么 component 就必須使用同一個(gè)注解
- module 的 provide 方法沒有使用 scope ,那么 component 和 module 是否加注解都無關(guān)緊要亲雪,可以通過編譯
- component的dependencies與component自身的scope不能相同勇凭,即組件之間的scope不同
- 沒有scope的component不能依賴有scope的component
- @Singleton 的生命周期依附于component,同一個(gè)module provide singleton ,不同component 也是不一樣