Android快速依赖注入框架Dagger2使用2

接着上一篇: http://blog.csdn.net/niubitianping/article/details/60878104

一、单例@Singleton

需要实例的类如果是单例的,需要在Component接口和Module类的方法使用@Singleton。

栗子: 新建一个SingleClass.java

public class SingleClass {
    //内容可以为空,仅做测试
}

1.1 Component接口添加@Singleton

在Component接口添加@Singleton注解

@Singleton
@Component(modules = LoginModule.class)
public interface LoginComponent {

    void inject(TestActivity activity);

}

1.2 Module类方法添加@Singleton

在Module类里面实例SingleClass的方法添加@Singleton注解

@Module
public class LoginModule {

    private Context mContext;   //供给LoginStore使用


    public LoginModule(Context mContext) {
        this.mContext = mContext;
    }



    @Provides
    @Singleton    //这里添加单例注解
    SingleClass provideSingleClass(){
        return new SingleClass();
    }

    ...(之前的代码缩略)

}

测试使用,在TestActivity中@Inject两个Singleclass

public class TestActivity extends Activity {


    @Inject
    SingleClass singleClassOne;

    @Inject
    SingleClass singleClassTwo;

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

        //DaggerLoginComponent.create().inject(this);

        //当Module需要构造方法传参的时候,使用builder的方式初始化Dagger。
        DaggerLoginComponent.builder()
                .loginModule(new LoginModule(this))  //loginModule这个方法是构建之后才有的
                .build()
                .inject(this);

        Log.e("@@", "singleClassOne: "+singleClassOne);
        Log.e("@@", "singleClassTwo: "+singleClassTwo);

    }

}

这时候可以看到输出的两个类的内存地址似乎一样的,证明这是同一个类,即单例类:

03-05 20:53:28.268 30247-30247/com.tpnet.dagger2test E/@@: singleClassOne: com.tpnet.dagger2test.five.SingleClass@c612337
03-05 20:53:28.268 30247-30247/com.tpnet.dagger2test E/@@: singleClassTwo: com.tpnet.dagger2test.five.SingleClass@c612337

ps注意: @Singleton 依赖于Component,如果两个不同的Component使用同一个Module来是哟个@Singleton创建单例,将会不是单例。

二、作用域@Scope

@Singleton可以看到他的源码为:

@Scope
@Documented
@Retention(RUNTIME)
public @interface Singleton {}

这里看到有一个@Scope,这个是用来给依赖划定作用域。

2.1 问题发掘

在单例的栗子中,我新建一个TwoActivity和GetInfoComponent,

GetInfoComponent.java

@Singleton
@Component(modules = LoginModule.class)
public interface GetInfoComponent {
    void inject(TwoActivity activity);
}

TwoActivity.java

public class TwoActivity extends Activity {

    @Inject
    LoginCtrl loginCtrl;

    @Inject
    SingleClass singleClass;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        DaggerGetInfoComponent.builder()
                .loginModule(new LoginModule(this))
                .build()
                .inject(this);

        Log.e("@@", "TwoActivity: "+singleClass);
    }
}

把TestActivity修改为:

可以看到怎么SingleClass这个地址怎么不对呢,不是单例吗?

03-06 14:55:29.556 7020-7020/com.tpnet.dagger2test E/@@: provideLoginCtrlOne被调用: 
03-06 14:55:29.556 7020-7020/com.tpnet.dagger2test E/@@: TestActivity: com.tpnet.dagger2test.six.SingleClass@421bd648
03-06 14:55:29.596 7020-7020/com.tpnet.dagger2test E/@@: provideLoginCtrlOne被调用: 
03-06 14:55:29.596 7020-7020/com.tpnet.dagger2test E/@@: TwoActivity: com.tpnet.dagger2test.six.SingleClass@421c4558

继续看下去

2.2 Scope分类

我们的应用有三个范围:

  • @Singleton: Singleton是Dagger已经定义好的,Application级别的Scope,只要application存活依赖就存活。
  • @UserScope: 只要用户会话是激活状态依赖就存活(在单个应用程序中启动)。重要的是:这个scope存活时间不会超过application本身。每一个新的app实例都会创建一个新的@UserScope(甚至app不同的启动间用户会话没有关闭)。
  • @ActivityScope: Activity范围,依赖于Activity,只要Activity界面存活依赖就存活。例如Activity销毁了,inject的component里面的module里面实例的对象都没了。

这里写图片描述

2.3 自定义Scope

利用Application级别的单例来实现单例,接下来解决上面的问题:

1. 新建AppModule.java

在这里提供SingleClass类。所以LoginModule里面提供Singleclass的方法需要去掉了。

@Module
public class AppModule {

    @Singleton
    @Provides 
    SingleClass providerSingleClass(){
        return new SingleClass();
    }

}

2. 新建AppComponent.java

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
    //把AppModule里面的SingleClass桥接出来
    SingleClass singleClass();
}

3. 自定义Scope

创建一个ActivityScope.java,作为自定义的Scope,用来标识LoginComponent和GetInfoComponent。

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScope {

}

4. 添加Component依赖

在LoginComponent和GetInfoComponent添加AppComponent的依赖,并且去掉@Singleton,添加自定义的ActivityScope注解

LoginComponent.java

@ActivityScope
@Component(modules = LoginModule.class,dependencies = AppComponent.class)
public interface LoginComponent {

    void inject(TestActivity activity);

}

GetInfoComponent.java

@ActivityScope
@Component(modules = LoginModule.class,dependencies = AppComponent.class)
public interface GetInfoComponent {
    void inject(TwoActivity activity);
}

5. 创建BaseApplication

完成上面的步骤之后,make 一下module,使得dagger生成DaggerAppComponent。

然后新建一个BaseApplication,用来注入AppComponent:


public class BaseApplication extends Application {


    AppComponent mAppComponent;

    @Override
    public void onCreate() {
        super.onCreate();

        mAppComponent = DaggerAppComponent.create();

    }

    public AppComponent getAppComponent(){
        return mAppComponent;
    }

}

然后在manifest添加BaseApplication。

6. 在Activity注入

TestActivity的注入改为;

DaggerLoginComponent.builder()
                .loginModule(new LoginModule(this))  //loginModule这个方法是构建之后才有的
                //添加appComponent,参数从BaseApplication获取
                .appComponent((((BaseApplication)getApplication()).getAppComponent()))
                .build()
                .inject(this);

TwoActivity的注入改为:

DaggerGetInfoComponent.builder()
                .loginModule(new LoginModule(this))
                //添加appComponent,参数从BaseApplication获取
                .appComponent(((BaseApplication)getApplication()).getAppComponent())
                .build()
                .inject(this);

最后运行看到结果,两个Activity里面实例的SingleClass的类相同:

03-06 16:10:29.937 21284-21284/com.tpnet.dagger2test E/@@: provideLoginCtrlOne被调用: 
03-06 16:10:29.937 21284-21284/com.tpnet.dagger2test E/@@: TestActivity: com.tpnet.dagger2test.six.SingleClass@421c4530
03-06 16:10:31.438 21284-21284/com.tpnet.dagger2test E/@@: provideLoginCtrlOne被调用: 
03-06 16:10:31.438 21284-21284/com.tpnet.dagger2test E/@@: TwoActivity: com.tpnet.dagger2test.six.SingleClass@421c4530

自定义Scope可以看看外国大牛的文章:
http://frogermcs.github.io/dependency-injection-with-dagger-2-custom-scopes/

三、@SubComponent

顾名思义,子@Component。类似@Component的dependencies。 @SubComponent可以在@Component里面进行返回获取。

dependencies不会继承范围,@Subcomponent会。@Subcomponent同时具备两种不同作用域的scope。

来个栗子:

3.1 创建子SubComponent

创建SingleClassTwo:

public class SingleClassTwo {
    //制作演示,可以为空方法
}

创建自定义Scope, UserScope.java:

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface UserScope {
}

创建ChildModule.java

@Module
public class ChildModule {

    @UserScope
    @Provides
    SingleClassTwo provideSingleClass(SingleClassOne singleClass){
        Log.e("@@", "provideSingleClass: singleClass是否为空:"+ (singleClass == null) );
        return new SingleClassTwo();
    }

}

创建ChildComponent.java:

@UserScope   //自定义Scope修饰
@Subcomponent(modules = ChildModule.class)
public interface ChildComponent {

    //这里的ThreeActivity在下面创建
    void inject(ThreeActivity activity);

}

ps注意: 如果父的Component使用了@Singleton, 子@Subcomponent 不能使用@Singleton。 就是SubComponent的范围 < 父Component的范围,需要自定义Scope,这里定义了一个UserScope。

3.2 创建父Component

创建SingleClassOne:

public class SingleClassOne {
    //制作演示,可以为空方法
}

创建FatherModule.java

@Module
public class FatherModule {

    @Singleton
    @Provides
    SingleClassOne providerSingleClass(){
        return new SingleClassOne();
    }

}

创建FatherComponent.java:

@Singleton
@Component(modules = FatherModule.class)
public interface FatherComponent {

    //父Component可以获取SubComponent
    ChildComponent getChildComponent();

}

3.3 使用

上面的代码创建完毕之后,make一下module,然后创建一个ThreeActivity.java

public class ThreeActivity extends Activity{


    @Inject
    SingleClassTwo singleClassTwo;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        DaggerOneComponent.create();
    }
}

运行ThreeActivity之后,没看到输出 singleClass是否为空 ,点解?

因为还没有注入ChildComponent,把ThreeActivity的onCreate改为下面的代码:

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        DaggerOneComponent.create()
                .getChildComponent()
                .inject(this);

    }

即可看到输出:

03-06 18:37:55.216 3414-3414/? E/@@: provideSingleClass: singleClass是否为空:false

四、懒加载Lazy和Provider

在上面的栗子中,在ThreeActivity.java的onCreate添加一句代码:

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);


        DaggerFatherComponent.create()
                .getChildComponent()
                .inject(this);

        Log.e("@@", "还没有进行创建singleClassTwo");


    }

可以看到下面的输出,证明了在inject的时候已经调用了ChildModule的provideSingleClass方法,简单说就是已经实例化了:

03-06 18:48:26.222 14898-14898/? E/@@: provideSingleClass: singleClass是否为空:false
03-06 18:48:26.222 14898-14898/? E/@@: 还没有进行创建singleClassTwo

4.1 Lazy

用Lazy标识的变量,在inject的时候并没有实例化,而是在t.get()的时候才实例化并返回。来个栗子:

创建Test.java

public class Test {

}

创建TestModule.java

@Module
public class TestModule {

    @Provides Test provideTest(){
        Log.e("@@", "调用了provideTest方法");
        return new Test();
    }

}

创建TestComponent.java

@Component(modules = TestModule.class)
public interface TestComponent {
    void inject(TestActivity activity);
}

make moudle,然后创建TestActivity.java

public class TestActivity extends Activity{

    @Inject Test test;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        DaggerTestComponent.builder().build().inject(this);
        Log.e("@@", "已经注入完成");
    }

}

这时候运行可以看到输出:

03-06 19:09:46.301 5187-5187/com.tpnet.dagger2test E/@@: 调用了provideTest方法
03-06 19:09:46.301 5187-5187/com.tpnet.dagger2test E/@@: 已经注入完成

上面的输出这是正常的,现在来修改一下TestActivtiy:

public class TestActivity extends Activity{

   // @Inject Test test;

    @Inject Lazy<Test> test;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        DaggerTestComponent.builder().build().inject(this);

        Log.e("@@", "已经注入完成");

        Log.e("@@", "开始第一次get: " + test.get().toString());
        Log.e("@@", "开始第二次get: " + test.get().toString());

    }

}

可以看到输出为下面的内容,表示inject的时候还没有进行TestModule里面的provideTest方法,是get的时候才实例化了,而且多次get得到的是同一个Test对象。

03-06 19:14:27.425 9846-9846/com.tpnet.dagger2test E/@@: 已经注入完成
03-06 19:14:27.425 9846-9846/com.tpnet.dagger2test E/@@: 调用了provideTest方法
03-06 19:14:27.425 9846-9846/com.tpnet.dagger2test E/@@: 开始第一次get: com.tpnet.dagger2test.eight.Test@421ae290
03-06 19:14:27.425 9846-9846/com.tpnet.dagger2test E/@@: 开始第二次get: com.tpnet.dagger2test.eight.Test@421ae290

4.2 Provider

使用这个类修饰的变量,也是懒加载,但是它每次get都会重新执行一遍provides实例化的方法。

修改一下上面的TestActivity:

public class TestActivity extends Activity{

    // @Inject Test test;

    //@Inject Lazy<Test> test;


    @Inject Provider<Test> test;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        DaggerTestComponent.builder().build().inject(this);

        Log.e("@@", "已经注入完成");

        Log.e("@@", "开始第一次get: " + test.get().toString());
        Log.e("@@", "开始第二次get: " + test.get().toString());

    }

}

可以看到输出为以下,表明了懒加载,每次get都会重新调用provides方法,产生新的对象:

03-06 19:18:09.852 13486-13486/com.tpnet.dagger2test E/@@: 已经注入完成
03-06 19:18:09.852 13486-13486/com.tpnet.dagger2test E/@@: 调用了provideTest方法
03-06 19:18:09.852 13486-13486/com.tpnet.dagger2test E/@@: 开始第一次get: com.tpnet.dagger2test.eight.Test@421af130
03-06 19:18:09.852 13486-13486/com.tpnet.dagger2test E/@@: 调用了provideTest方法
03-06 19:18:09.852 13486-13486/com.tpnet.dagger2test E/@@: 开始第二次get: com.tpnet.dagger2test.eight.Test@421af520

4.3 懒加载注意

Provide不是规定死了每次get都是新的对象。 例如单例,每次get还是同一个对象。在一的栗子的ThreeActivity进行修改:

public class ThreeActivity extends Activity{


    //@Inject SingleClassTwo singleClassTwo;


    @Inject Provider<SingleClassTwo> singleClassTwo;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);


        DaggerFatherComponent.create()
                .getChildComponent()
                .inject(this);


        Log.e("@@", "还没有进行创建singleClassTwo");

        Log.e("@@", "get地址1: "+singleClassTwo.get().toString());
        Log.e("@@", "get地址2: "+singleClassTwo.get().toString());


    }
}

可以看到输出内容为以下,两次get的对象还是同一个:

03-06 19:22:27.944 17698-17698/? E/@@: 还没有进行创建singleClassTwo
03-06 19:22:27.944 17698-17698/? E/@@: provideSingleClass: singleClass是否为空:false
03-06 19:22:27.944 17698-17698/? E/@@: get地址1: com.tpnet.dagger2test.seven.SingleClassTwo@421b0860
03-06 19:22:27.944 17698-17698/? E/@@: get地址2: com.tpnet.dagger2test.seven.SingleClassTwo@421b0860

五、总结Dagger2注意点

  • @Component接口的inject方法接收的参数和传递的参数类型必须一致,不能定义为MainActivty,然后传递Activity,会导致注入失败,对象为空

  • @Component接口关联的modules中不能有重复的provide类型

  • @Module类的provide方法使用了Scope,那么对应的@Component接口也必须使用同一个注解。

  • @Component的dependencies与@Component自身的Scope不能相同。需要自定义Scope

  • @Singleton的组件不能依赖其他Scope组件,只能其他的Scope组件依赖Singleton组件。

  • 没有Scope的@Component接口不能依赖有Scope的@Component接口

  • 一个@Component接口不能同时有多个@Scope(Subcomponent除外)

  • @Singleton的生命周期依赖于@Component@Component的注入类销毁了, @Singleton实例化的类也会没了。

  • @SubComponent的Scope范围不能大于他的父Component。

  • 懒加载Provider根据@Provides方法实现的不同,get到的对象可能是同一个,可能是不同。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KeepStudya

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值