本文介绍了Dagger 2 中@Scope和@Subcomponent的使用。

本文首发:http://yuweiguocn.github.io/

《清明》
清明时节雨纷纷,路上行人欲断魂。
借问酒家何处有,牧童遥指杏花村。
-唐,杜牧

Dagger 2 在 Android 上的使用(一)
Dagger 2 在 Android 上的使用(二)
Dagger 2 在 Android 上的使用(三)
Dagger 2 在 Android 上的使用(四)
Dagger 2 在 Android 上的使用(五)
Dagger 2 在 Android 上的使用(六)

生命周期

我们可以使用注解@Scope来管理依赖的生命周期。它和注解@Qualifier一样是用来自定义注解的,注解@Scope的默认实现是@Singleton,用于在Component实例中保持单例。如果我们在Application类中持有Component的引用,就实现了应用内保持单例。注意需要在Component上和提供实例的方法上同时添加@Scope注解才会起作用。接下来看一个使用的例子:

首先需要在Component类添加注解@Singleton

@Singleton@Component(modules = PeopleModule.class)public interface PeopleComponent {    void inject(PeopleActivity activity);}

然后在Module类提供实例的方法上也需要添加注解@Singleton

@Modulepublic abstract class PeopleModule {    @Binds    @Study    @Singleton    abstract People bindStudent(Student student);}

在Activity中同时注入两个成员变量:

public class PeopleActivity extends Activity {    @Inject    @Study    People student;    @Inject    @Study    People student2;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        DaggerPeopleComponent.create().inject(this);        Log.d("debug", student.toString());        Log.d("debug", student2.toString());    }}

可以看到注入了两个变量,是同一个实例,打印日志输出:

2018-12-12 17:57:50.287 30809-30809/io.github.yuweiguocn.dagger D/debug: 1io.github.yuweiguocn.dagger.test.Student@be59fd92018-12-12 17:57:50.287 30809-30809/io.github.yuweiguocn.dagger D/debug: 2io.github.yuweiguocn.dagger.test.Student@be59fd9

生成的代码:

public final class DaggerPeopleComponent implements PeopleComponent {  private Provider bindStudentProvider;  private DaggerPeopleComponent(Builder builder) {    initialize(builder);  }  ...  @SuppressWarnings("unchecked")  private void initialize(final Builder builder) {    this.bindStudentProvider = DoubleCheck.provider((Provider) Student_Factory.create());  }  ...  private PeopleActivity injectPeopleActivity(PeopleActivity instance) {    PeopleActivity_MembersInjector.injectStudent(instance, bindStudentProvider.get());    PeopleActivity_MembersInjector.injectStudent2(instance, bindStudentProvider.get());    return instance;  }  ...}

这里和Lazy注入一样,都是使用DoubleCheck类保证了实例的唯一
通常我们会根据实例的生命周期自定义Scope,例如:ApplicationScope、ActivityScope和FragmentScope等。
如果是通过在构造方法添加@Inject注解这种方法提供的实例,可以在对应类上添加@Scope注解管理依赖的生命周期,例如:

@Singletonpublic class Student extends People {    @Inject    public Student() {    }    @Override    String doWhat() {        return "study";    }}

注解@Subcomponent

Component类只能应用一个@Scope注解,如果我们想使用多个@Scope注解时,可以使用@SubComponent实现,使用Subcomponent的另一原因是用于拆分层级。

首先自定义两个Scope:

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

然后使用@Subcomponent注解定义两个子组件,添加自定义的@ActivityScope注解,指定Module类,提供Activity的注入方法:

@ActivityScope@Subcomponent(modules = WorkerModule.class)public interface WorkerComponent {    void inject(WorkerActivity activity);}@ActivityScope@Subcomponent(modules = StuModule.class)public interface StuComponent {    void inject(StuActivity activity);}

在父组件中暴露子组件,添加自定义的@AppScope注解,注意子组件不能与父组件应用相同的@Scope注解,子组件的生命周期严格小于父组件的生命周期,兄弟组件可以使用相同的@Scope注解(但实际上具有不同的生命周期实例):

@AppScope@Componentpublic interface PeopleComponent {    StuComponent student();    WorkerComponent worker();    @Component.Builder    interface Builder{        PeopleComponent build();        @BindsInstance        Builder application(Application application);    }}

在子组件指定的Module中提供实例的方法上添加自定义的@ActivityScope注解:

@Modulepublic abstract class StuModule {    @Binds    @ActivityScope    abstract People bindStudent(Student student);}@Modulepublic abstract class WorkerModule {    @Binds    @ActivityScope    abstract People bindWroker(Worker worker);}

在子组件指定的Module提供的实例添加对父组件提供实例的依赖:

public class Student extends People {    private Application app;    @Inject    public Student(Application app) {        this.app = app;    }    @Override    String doWhat() {        return "study app: " + app.toString();    }}public class Worker extends People {    private Application app;    @Inject    public Worker(Application app) {        this.app = app;    }    @Override    String doWhat() {        return "work app: " + app.toString();    }}

在Application中构建父组件:

public class App extends Application {    private static App app;    private PeopleComponent component;    @Override    public void onCreate() {        super.onCreate();        app = this;        component = DaggerPeopleComponent.builder().application(this).build();    }    public static App getApp() {        return app;    }    public PeopleComponent getComponent() {        return component;    }}

最后在Activity中使用Application构建的父组件中提供的子组件进行注入:

public class StuActivity extends Activity {    @Inject    Student student;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        App.getApp().getComponent().student().inject(this);        Log.d("debug", student.doWhat());    }}public class WorkerActivity extends AppCompatActivity {    @Inject    Worker worker;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        App.getApp().getComponent().worker().inject(this);        Log.d("debug", worker.doWhat());    }}

总结

  • 可以使用注解@Scope管理依赖的生命周期,@Scope的默认实现是@Singleton,可以在Component中保持单例,需要在Component上和提供实例的方法上同时添加注解才会起作用。原理是通过DoubleCheck类保证了实例的唯一。通常使用多个@Scope时会根据实例生命周期自定义,如:AppScope、ActivityScope、FragmentScope等。
  • 通过在构造方法添加@Inject注解提供实例的,可以在对应类上添加@Scope注解管理依赖生命周期。
  • Component类只能应用一个@Scope注解,如果需要使用多个@Scope,可以使用@Subcomponent实现,使用@Subcomponent的另一原因是用于拆分层级。
  • 子组件Subcomponent不能和父组件使用相同的@Scope注解,子组件的生命周期严格小于父组件的生命周期,兄弟组件可以使用相同的@Scope注解(但实际上具有不同生命周期的实例)。

参考

  • https://google.github.io/dagger/
  • https://www.jianshu.com/p/24af4c102f62
  • http://www.cnblogs.com/tiantianbyconan/p/5092083.html
  • https://blog.csdn.net/soslinken/article/details/70231089

更多相关文章

  1. Dagger 2 在 Android(安卓)上的使用(四)
  2. [实例教程] 用python开发android应用
  3. Android概述--期末考试Android理论筛查
  4. android布局---android:layout_weight
  5. Application Fundamentals
  6. 详解 Android(安卓)的 Activity 组件
  7. Android的四种启动方式
  8. Android(安卓)Stagefright
  9. Activity的四种启动模式和onNewIntent()

随机推荐

  1. 表数据量大读写缓慢如何优化(2)【查询分离
  2. 字符函数和字符串函数(C语言)(1,2,3)
  3. 正则表达式与文本处理工具 脚本实战
  4. VS库函数的找寻
  5. 学习C语言第五天(循环结构课后练习)
  6. 【体系课】数据可视化入门到精通 打造前
  7. jQuery - Ajax - Timeout 属性不生效的问
  8. c语言学习打卡
  9. PMM配置监控PG数据库
  10. JAVA线程的那些事?