目錄
3.讓dagger知道從哪兒獲取依賴,注入依賴到哪兒:構造方法提供依賴
3.讓dagger知道從哪兒獲取依賴,注入依賴到哪兒:Module類提供依賴
前置:
依賴倒置原則、控制反轉(Inversion of Control)、依賴注入(Dependency Injection) 有一定的瞭解。
依賴倒置:高層不依賴低層而依賴抽象,抽象不依賴實現類。換言之,解耦具體實現,提升擴展性。
控制反轉:降低類與類耦合度。包括:依賴注入和依賴查找兩種實現方式。
依賴注入:不直接在需要依賴的地方new創建依賴,將依賴部分與邏輯分離、解耦。
幾個明顯的坑:
- Component inject(container c) 容器必須傳入與你實際調用inject相同的類。也就是說不能c傳入BaseActivity,實際調用在XActivity。
- 一個容器不能注入多個相同依賴,或者用@qualifier註明不同Provides。
- 很多註解都需要配對使用,否則報錯,特別注意。
三種常用的依賴注入方式:
A依賴B。其實三種方式平時也在用,只是沒有特別去關注。
構造器注入:
public class InjectionA {
private B b;
public InjectionA(B b) {
this.b = b;
}
}
setter方法注入:
public class InjectionA {
private B b;
public void setB(B b) {
this.b = b;
}
}
接口注入:
interface Inject{
void inject(B b);
}
public class InjectionA implements Inject{
private B b;
@Override
public void inject(B b) {
this.b = b;
}
}
Dagger簡單注入:
1.依賴創建:構造方法提供依賴
package com.fengzhen.dagger;
import javax.inject.Inject;
public class User {
String name;
// 提供依賴
@Inject
public User() {
this.name = "張三";
}
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
1.依賴創建:Module類提供依賴
package com.fengzhen.dagger;
public class User2 {
String name;
public User2(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.fengzhen.dagger;
import dagger.Module;
import dagger.Provides;
@Module
public class ActivityModule {
@Provides
User2 provider(){
return new User2("李四");
}
}
2.依賴注入位置:屬性注入 User注入
package com.fengzhen.dagger;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import javax.inject.Inject;
public class MainActivity extends AppCompatActivity {
private TextView mTV;
private Button mBtn;
// 哪裏需要依賴?
@Inject
User mUser;
@Inject
User2 mUser2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTV = (TextView) findViewById(R.id.tv);
mBtn = (Button) findViewById(R.id.btn);
mBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mTV.setText(/*mUser.getName() + */mUser2.getName());
}
});
DaggerActivityComponet.create().inject(this);
}
}
2.依賴注入位置:方法注入 User2注入
不常用,一般用於需要this初始化的情況。
package com.fengzhen.dagger;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import javax.inject.Inject;
public class MainActivity extends AppCompatActivity {
private TextView mTV;
private Button mBtn;
// 哪裏需要依賴?
@Inject
User mUser;
User2 mUser2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("fengzhen", "onCreate: ==onCreate方法被調用");
setContentView(R.layout.activity_main);
mTV = (TextView) findViewById(R.id.tv);
mBtn = (Button) findViewById(R.id.btn);
mBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mTV.setText(mUser.getName() + mUser2.getName());
}
});
DaggerActivityComponet.create().inject(this);
}
@Inject
public void setmUser2(User2 mUser2) {
Log.i("fengzhen", "setmUser2: ==set方法被調用");
this.mUser2 = mUser2;
}
}
3.讓dagger知道從哪兒獲取依賴,注入依賴到哪兒:構造方法提供依賴
package com.fengzhen.dagger;
import dagger.Component;
// 如何將依賴注入給對象
@Component()
public interface ActivityComponet {
void inject(MainActivity mainActivity);
}
3.讓dagger知道從哪兒獲取依賴,注入依賴到哪兒:Module類提供依賴
這裏@Componet傳入了提供依賴的Class
package com.fengzhen.dagger;
import dagger.Component;
// 如何將依賴注入給對象
@Component(modules = ActivityModule.class)
public interface ActivityComponet {
void inject(MainActivity mainActivity);
}
4.生成的代碼
生成路徑:dagger2demo/build/generated/source/apt/debug/
User_Factory: 構造方法使用@Inject生成,靜態工廠創建依賴實例。
ActivityModule_ProviderFactory: 根據Module類靜態工廠創建依賴實例。
MainActivity_membersInjector: 拿到創建的依賴注入需要依賴的位置。
DaggerActivityComponet:實現ActivityComponet接口,實現具體的關聯邏輯。
關鍵字
@Inject
@Target({ METHOD, CONSTRUCTOR, FIELD }) @Retention(RUNTIME) @Documented public @interface Inject {}
1.方法上
類似方法注入,構造器執行後調用此方法。
2.構造器上
提供依賴/注入依賴,視具體情況定。
3.屬性上
最常用的屬性注入。
@Componet 單獨依賴(modules)
@Retention(RUNTIME) @Target(TYPE) @Documented public @interface Component { Class<?>[] modules() default {}; Class<?>[] dependencies() default {}; @Target(TYPE) @Documented @interface Builder {} }
void inject()
指定注入目標,查找@Inject註解,注入對象。
modules
傳入Module方式的提供依賴類。
@Module、@Provides
@Module表明該類可以提供依賴,@Provides代表了具體提供不同依賴的方法。
@Named
提供相同依賴的不同實例,用來標記類別。
@Module
public class ActivityModule {
@Provides
@Named("user2")
IUser provider(){
return new User2("李四");
}
@Provides
@Named("user1")
IUser providerUser(){
return new User("張三");
}
}
// 哪裏需要依賴?
@Inject
@Named("user1")
IUser mUser;
@Inject
public void setmUser2(@Named("user2") IUser mUser2) {
Log.i("fengzhen", "setmUser2: ==set方法被調用");
this.mUser2 = mUser2;
}
@Qualifier
功能類似於@named,用來自定義註解,實現區分的效果。
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface AUser {}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface AUser2 {}
@Module
public class ActivityModule {
@Provides
// @Named("user2")
@AUser2
IUser provider(){
return new User2("李四");
}
@Provides
// @Named("user1")
@AUser
IUser providerUser(){
return new User("張三");
}
}
// 哪裏需要依賴?
@Inject
// @Named("user1")
@AUser
IUser mUser;
@Inject
public void setmUser2(/*@Named("user2")*/@AUser2 IUser mUser2) {
Log.i("fengzhen", "setmUser2: ==set方法被調用");
this.mUser2 = mUser2;
}
@Componet 嵌套依賴(dependencies)
已經瞭解了 module 的使用。dependencies可以將Componet相互嵌套起來使用。
將整個流程代碼貼一次。省略IUser、User、User2、AUser、AUser2。
Store
package com.fengzhen.dagger.subcomponent;
import com.fengzhen.dagger.IUser;
public class Store {
IUser user;
public Store(IUser user) {
this.user = user;
}
public String getUserName() {
return user.getName();
}
}
IUser依賴提供:UserModule
package com.fengzhen.dagger;
import dagger.Module;
import dagger.Provides;
@Module
public class UserModule {
@Provides
@AUser2
IUser provider() {
return new User2("User2李四");
}
@Provides
@AUser
IUser providerUser() {
return new User("User張三");
}
}
IUser註解組件:IUserComponet
@Component(modules = UserModule.class)
public interface IUserComponet {
@AUser
IUser getUser();
@AUser2
IUser getUser2();
}
Store依賴提供:StoreModule
@Module
public class StoreModule {
@Provides
Store provideStore(@AUser2 IUser user){
return new Store(user);
}
}
Store註解組件:StoreComponet
這裏StoreComponet依賴於UserComponet,寫法如下:
@Component(modules = StoreModule.class,
dependencies = IUserComponet.class)
public interface StoreComponent {
Store getStore();
}
Container指定組件:ActivityComponet
如果Activity仍需要注入IUser,取消註釋即可。
// 如何將依賴注入給對象
@Component(/*modules = UserModule.class,*/
dependencies = StoreComponent.class)
public interface ActivityComponet {
void inject(MainActivity mainActivity);
}
Container注入
DaggerActivityComponet.builder()
.storeComponent(DaggerStoreComponent.builder()
.iUserComponet(DaggerIUserComponet.create())
.build())
.build()
.inject(this);
即。每個Bean、Module、Componet爲整體,缺一不可,可通過dependencies將組與組連接嵌套在一起。
@Subcomponet 嵌套依賴
@Componet 嵌套依賴的更加緊密的實現方式。只需要修改Componet實現
@Component(modules = UserModule.class)
public interface IUserComponet {
//
// @AUser
// IUser getUser();
//
// @AUser2
// IUser getUser2();
StoreComponent plus(StoreModule storeModule);
}
//@Component(modules = StoreModule.class,
// dependencies = IUserComponet.class)
@Subcomponent(modules = StoreModule.class)
public interface StoreComponent {
// Store getStore();
ActivityComponet plus();
}
// 如何將依賴注入給對象
//@Component(modules = UserModule.class,
// dependencies = StoreComponent.class)
@Subcomponent
public interface ActivityComponet {
void inject(MainActivity mainActivity);
}
Container注入
DaggerIUserComponet.create()
.plus(new StoreModule())
.plus()
.inject(this);
兩者區別:
- dependencies能單獨使用,而Subcomponent必須由Component調用方法獲取
- Container使用差別,dependencies使用creat(),Subcomponent使用new。
- dependencies可將低層User也進行注入,Subcomponent聯繫緊密不能注入。
@Singleton
實現依賴單例。每次都提供同一個實例,實現與Componet同生命週期的單例。
且必須配對使用,Module和Componet必須配對使用否則報錯。
@Scope @Documented @Retention(RUNTIME) public @interface Singleton {}
DaggerActivityComponet.create().inject(this);
StoreComponent component = DaggerStoreComponent.create();
Store containerA = new Store();
Store containerB = new Store();
component.inject(containerA);
component.inject(containerB);
Log.i("fengzhen", "onCreate: " + mUser2.toString());
Log.i("fengzhen", "onCreate: " + containerA.user.toString());
Log.i("fengzhen", "onCreate: " + containerB.user.toString());
分別創建兩個Componet,分別注入Activity和兩個Store,打印結果可見:
兩個Store的User是一個實例,且與Activity的User不是一個實例。
@Scope
@Singleton是@Scope的一種,也是官方給出來的,我們也可以自定義Scope實現我們想要的生命週期。
定義一個App全局單例。
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface AppLifecycle {
}
package com.fengzhen.dagger;
import android.app.Application;
import com.fengzhen.dagger.scope.ConfigComponet;
import com.fengzhen.dagger.scope.DaggerConfigComponet;
public class App extends Application {
private static ConfigComponet mConfigComponet;
@Override
public void onCreate() {
super.onCreate();
// 與App生命週期進行綁定,實現全App單例
mConfigComponet = DaggerConfigComponet.create();
}
/**
* 具體容器進行自定義注入
*/
public static ConfigComponet getConfigComponet() {
return mConfigComponet;
}
}
MapKey和Lazy用到了再補充。。。。。