美文网首页Android开发Android技术知识Android开发
Dagger 2 在 Android 上的使用(五)

Dagger 2 在 Android 上的使用(五)

作者: 于卫国 | 来源:发表于2019-01-19 22:44 被阅读5次

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

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

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

    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

    @Module
    public 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@be59fd9
    2018-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<People> 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等。

    注解@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
    @Component
    public interface PeopleComponent {
    
        StuComponent student();
    
        WorkerComponent teacher();
    
        @Component.Builder
        interface Builder{
            PeopleComponent build();
    
            @BindsInstance
            Builder application(Application application);
        }
    }
    

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

    @Module
    public abstract class StuModule {
    
        @Binds
        @ActivityScope
        abstract People bindStudent(Student student);
    }
    
    @Module
    public 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().teacher().inject(this);
            Log.d("debug", worker.doWhat());
        }
    }
    
    

    总结

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

    参考

    相关文章

      网友评论

        本文标题:Dagger 2 在 Android 上的使用(五)

        本文链接:https://www.haomeiwen.com/subject/cysarqtx.html