Dagger2的理解和使用

Android:dagger2让你爱不释手-基础依赖注入框架篇
Android:dagger2让你爱不释手-重点概念讲解、融合篇
Android:dagger2让你爱不释手-终结篇

Dagger 2 完全解析(一),Dagger 2 的基本使用与原理
Dagger 2 完全解析(二),进阶使用 Lazy、Qualifier、Scope 等
Dagger 2 完全解析(三),Component 的组织关系与 SubComponent
Dagger 2 完全解析(四),Android 中使用 Dagger 2
Dagger 2 完全解析(五),Kotlin 中使用 Dagger 2
Dagger 2 完全解析(六),dagger.android 扩展库的使用

1、Component的使用

作为桥连接依赖和被依赖对象。
每一个Component都会创建一个对应的DaggerComponent
@Inject注解的构造函数会创建对应类的Factory,用于实例化该类

/**
 * 药物
 */

public class Medicine {

    @Inject
    public Medicine() {
    }

    public void treat() {
        LogUtil.e("开始治疗");
    }
}
/**
 * 注射器
 */

@Component
public interface Injector {
    //注射动作,指定病患
    void inject(MainActivity mainActivity);
}
/**
 * 病患
 */
public class MainActivity extends AppCompatActivity {

    @Inject
    Medicine mMedicine;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //口服
        Medicine medicine = new Medicine();
        medicine.treat();
        //打针
        DaggerInjector.create().inject(this);
        mMedicine.treat();
    }
}  

2、Module使用场景

1、没有构造函数
2、有参构造
3、三方库的类
每一个@Provides注解的方法都会创建一个Factory用来提供实例化对象给DaggerComponent使用。
@Provides注解的方法所需要的参数会优先从Module的其他provide中取。

@Module
public class ModuleClass {

    @Provides
    Gson provideGson() {
        return new Gson();
    }
}
@Component(modules = ModuleClass.class)
public interface ComponentClass {
    void inject(MainActivity2 mainActivity);
}
public class MainActivity2 extends AppCompatActivity {

    @Inject
    Gson mGson;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        DaggerComponentClass.create().inject(this);
        String s = mGson.toJson(new Medicine());
        LogUtil.e(s);
    }
}

3、@Scope作用域

@Scope是一个元注解,用于注解自定义注解,可以确定注入的实例的生命周期,并在声明周期内保持实例唯一。使用时Module 中 provide 方法中的 Scope 注解必须和 与之绑定的 Component 的 Scope 注解必须一样,否则作用域不同会导致编译时会报错。
作用域的原理,其实是让生成的依赖实例的生命周期与 Component 绑定,Scope 注解并不能保证生命周期,要想保证赖实例的生命周期,需要确保 Component 的生命周期。

@Singleton是通过@Scope定义的一个新的注解,能够使同一个Component中的对象保持唯一,保持唯一的条件是通过@Scope标记的注解相同。

@Singleton并没有创建单例的能力,起作用为
1、保证Component和Module是匹配的。
2、代码可读性。

以页面划分component,一个页面一个component,但这并不是一定的,有时候多页面会共用一个component,因为它们需要的参数一致。

一个全局component用来管理管理整个App的全局类实例。

@Scope //注明是Scope 
@Documented  //标记在文档 
@Retention(RUNTIME)  // 运行时级别
public @interface Singleton {}
@Module
public class FactoryModule {

    @Provides
    Gson provideGson() {
        LogUtil.e("创建Gson对象");
        return new Gson();
    }

}
@Component(modules = FactoryModule.class)
public interface BridgeComponent {
    Gson getGson();
}
public class App extends Application {

    public static BridgeComponent sBridgeComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        sBridgeComponent = DaggerBridgeComponent.create();
    }

}
@Module
public class ActivityModule {

    @Singleton
    @Provides
    Person5 providesPersonWithString() {
        return new Person5("xls");
    }

}
@Singleton
@Component(dependencies = BridgeComponent.class, modules = ActivityModule.class)
public interface ActivityComponent {
    void inject(MainActivity3 mainActivity);
}
public class MainActivity3 extends AppCompatActivity {

    @Inject
    Person5 mPerson5;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        DaggerActivityComponent.builder().bridgeComponent(App.sBridgeComponent).activityModule(new ActivityModule()).build().inject(this);
        Gson gson = App.sBridgeComponent.getGson();
        LogUtil.e(gson.toJson(mPerson5));
    }
}

4、有参构造

MainModule -->providesPerson()中new Person(context)不能直接使用this.context,Module中查找返回Context的方法,并注入。此场景默认调用providesContext方法获取context。

public class Person {

    public String name = "张三";
    public int age = 23;

    private Context context;

    public Person(Context context) {
        LogUtil.e("a person created with context:" + context);
    }
}
@Module
public class MainModule {

    private Context context;

    public MainModule(Context context) {
        this.context = context;
    }

    @Provides
    public Context providesContext() {
        return this.context;
    }

    @Provides
    public Person providesPerson(Context context) {
        LogUtil.e("person from module");
        return new Person(context);
    }
}
@Component(modules = MainModule.class)
public interface MainComponent {
    void inject(MainActivity4 mainActivity4);
}
public class MainActivity4 extends AppCompatActivity {

    @Inject
    Person mPerson;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerMainComponent.builder().mainModule(new MainModule(getApplicationContext())).build().inject(this);
        String s = App.getInstance().mGson.toJson(mPerson);
        LogUtil.e(s);
    }
}

5、自定义标记、限定符

用于区分同类的不同依赖

public class Person5 {

    public String name = "张三";
    public int age = 23;
    public Context context;

    public Person5(Context context) {
        this.context = context;
        LogUtil.e("a person created with context:" + context);
    }

    public Person5(String name) {
        this.name = name;
        LogUtil.e("a person created with name:" + name);
    }
}
@Module
public class MainModule5 {
    private Context context;

    public MainModule5(Context context) {
        this.context = context;
    }

    @Provides
    public Context providesContext() {
        return this.context;
    }

    //    @Named("context")
    @PersonForContext
    @Provides
    public Person5 providesPersonWithContext(Context context) {
        return new Person5(context);
    }

    //    @Named("string")
    @PersonForName
    @Provides
    public Person5 providesPersonWithName() {
        return new Person5("yxm");
    }

}
@Component(modules = MainModule5.class)
public interface MainComponent5 {
    void inject(MainActivity5 mainActivity5);
}
public class MainActivity5 extends AppCompatActivity {

    //    @Named("string")
    @PersonForName
    @Inject
    Person5 p1;

    //    @Named("context")
    @PersonForContext
    @Inject
    Person5 p2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerMainComponent5.builder().mainModule5(new MainModule5(getApplicationContext())).build().inject(this);
        String s1 = App.getInstance().mGson.toJson(p1);
        LogUtil.e(s1);
        //java.lang.SecurityException: Can not make a java.lang.reflect.Method constructor accessible
//        String s2 = App.getInstance().mGson.toJson(p2);
//        LogUtil.e(s2);
    }
}
@Qualifier  // 关键词
@Retention(RetentionPolicy.RUNTIME)  // 运行时仍可用
public @interface PersonForContext {
    // Context 对象的注解
}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface PersonForName {
    // name 对象的注解
}

6、Provider、Lazy

沿用demo5部分文件

@Module
public class MainModule5 {
    private Context context;

    public MainModule5(Context context) {
        this.context = context;
    }

    @Provides
    public Context providesContext() {
        return this.context;
    }

    //    @Named("context")
    @PersonForContext
    @Provides
    public Person5 providesPersonWithContext(Context context) {
        return new Person5(context);
    }

    //    @Named("string")
    @PersonForName
    @Singleton
    @Provides
    public Person5 providesPersonWithName() {
        return new Person5("yxm");
    }

}
@Singleton
@Component(modules = MainModule5.class)
public interface MainComponent5 {
    void inject(MainActivity5 mainActivity5);
}

public class MainActivity5 extends AppCompatActivity {

    //    @Named("string")
    @PersonForName
    @Inject
    Person5 p1;

    @PersonForName
    @Inject
    Provider<Person5> providerPerson;

    //    @Named("context")
    @PersonForContext
    @Inject
    Lazy<Person5> lazyPerson;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerMainComponent5.builder().mainModule5(new MainModule5(getApplicationContext())).build().inject(this);
        Person5 person5 = lazyPerson.get();// 调用该方法时才会去创建Person,以后每次调用获取的是同一个对象
        Person5 person6 = lazyPerson.get();
        Person5 person7 = providerPerson.get();// 调用该方法时才回去创建Person1,以后每次调用都会重新加载Module中的具体方法,根据Module中的实现,可能相同,可能不相同。加@Singletom注解,创建一次
        Person5 person8 = providerPerson.get();

        String s1 = App.getInstance().mGson.toJson(p1);
        LogUtil.e(s1);
        //java.lang.SecurityException: Can not make a java.lang.reflect.Method constructor accessible
//        String s2 = App.getInstance().mGson.toJson(p2);
//        LogUtil.e(s2);
    }
}

总结

1、将实例化操作抽离出来,达到解耦的效果
2、单例无需考虑线程是否安全

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342