zoukankan      html  css  js  c++  java
  • Dagger2 (二) 进阶篇

    一.作用域Scope

    之前了解RoboGuice的时候,我们知道它默认给我们提供了几个注解,ContextSingleton和Singleton,但是Dagger2更为灵活,只有javax包中提供的Singleton注解。更为强大的是,我们可以自定义作用域。

    首先我们定义一个运行时的注解。

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

    我们新增加一个Module,专门为Activity中提供依赖。

    @Module
    public class ActivityUtilModule {
        private Activity activity;
    
        public ActivityUtilModule(Activity activity) {
            this.activity = activity;
        }
    
        @Provides
        public Resources provideResource() {
            return activity.getResources();
        }
    
        @Provides
        @PerActivity
        public Toaster provideToaster() {
            return new Toaster(activity);
        }
    }
    

    然后我们新增一个Component来承载这个Module,注意,这里我用了dependencies,这样Component就可以传递依赖到子Component。

    @PerActivity
    @Component(dependencies = ApplicationComponent.class, modules = ActivityUtilModule.class)
    public interface ActivityComponent {
        void inject(MainActivity activity);
    }
    

    我们修改ApplicationComponent,让其不再直接注入到Activity中,而使用ActivityComponent来注入。

    在MainActivity中我们这样写:

    public class MainActivity extends AppCompatActivity {
        private static final String TAG = "MainActivity";
    
        @Inject
        Toaster toaster;
    
        @Inject
        @Named("app")
        Context context;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            ActivityComponent activityComponent = DaggerActivityComponent.
                    builder().
                    activityUtilModule(new ActivityUtilModule(this)).
                    applicationComponent(component()).
                    build();
            activityComponent.inject(this);
    
            toaster.longToast(context.getPackageName());
    
        }
    
        protected ApplicationComponent component() {
            return ((DaggerApplication) getApplication()).Component();
        }
    }
    

    运行成功后,会弹出包名。相信到这里,大家还是一头雾水。

    当我们去掉ActivityComponent中的PerActivity注解时,我们就会发现,编译出错了:这里告诉我们没依赖这个注解,就使用了这个模块,这是编译时期就会不通过的。这里也暴露了作用域的作用,约束一个模块的注入器组件。且在这个组件中使用这个Module时,提供的这个Provider是单例。即组件模块内单例。

    Error:(10, 1) 错误: github.pedroneer.dagger2.dagger.ActivityComponent (unscoped) may not reference scoped bindings:
    @Provides @github.pedroneer.dagger2.dagger.PerActivity github.pedroneer.dagger2.Toaster github.pedroneer.dagger2.dagger.ActivityUtilModule.provideToaster()
    

    好,也许到这里还是不懂,先看下这个例子。

    我们将BaseActivity中注入了依赖。

    public class BaseActivity extends FragmentActivity {
    
        @Inject
        Toaster toaster;
    
        @Inject
        @Named("app")
        Context context;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            ActivityComponent activityComponent = DaggerActivityComponent.
                    builder().
                    activityUtilModule(new ActivityUtilModule(this)).
                    applicationComponent(component()).
                    build();
            activityComponent.inject(this);
    
            toaster.longToast(context.getPackageName());
        }
    
        private ApplicationComponent component() {
            return ((DaggerApplication) getApplication()).Component();
        }
    }
    

    此外,我们MainActivity和SecondActivity都继承自BaseActivity,这也符合我们平时的做法。

    public class MainActivity extends BaseActivity {
        private static final String TAG = "toaster";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            toaster.longToast(context.getPackageName());
            Log.d(TAG, "onCreate: " + toaster.hashCode());
            Intent intent = new Intent(this, SecondActivity.class);
            startActivity(intent);
        }
    }
    
    public class SecondActivity extends BaseActivity {
        private static final String TAG = "toaster";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            toaster.longToast(context.getPackageName());
            Log.d(TAG, "onCreate: " + toaster.hashCode());
        }
    }
    

    那接下来我们打印的两个hashCode会是同一个么?

    当然不是。

    03-21 00:32:57.706 12716-12716/github.pedroneer.dagger2 D/toaster: onCreate: 531688530
    03-21 00:32:57.866 12716-12716/github.pedroneer.dagger2 D/toaster: onCreate: 204017154
    

    因为我们在BaseActivity中就指定了每次创建时都会创建一个新的ActivityComponent,但ActivityComponent中依赖的ApplicationComponent确是一个,因为我们每次都是从DaggerApplication中拿这个对象注入的。

    也就是说,注解了PerActivity的对象,只在一个模块的组件生命周期内单例。

    再看下面的例子:

    我们提供custom和the两种toaster。

    @Module
    public class ActivityUtilModule {
        private Activity activity;
    
        public ActivityUtilModule(Activity activity) {
            this.activity = activity;
        }
    
        @Provides
        public Resources provideResource() {
            return activity.getResources();
        }
    
        @Provides
        @PerActivity
        @Named("custom")
        public Toaster provideToaster() {
            return new Toaster(activity);
        }
    
        @Provides
        @Named("the")
        public Toaster provideTheToaster() {
            return new Toaster(activity);
        }
    }
    

    并在ActivityComponent中提供依赖。

    @PerActivity
    @Component(dependencies = ApplicationComponent.class, modules = ActivityUtilModule.class)
    public interface ActivityComponent {
        void inject(BaseActivity activity);
    
        @Named("custom")
        Toaster theToaster();
    
        @Named("the")
        Toaster toaster();
    }
    

    最后我们在MainActivity中查看下多次获取这个两个依赖的情况。

    public class MainActivity extends BaseActivity {
        private static final String TAG = "toaster";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Log.d(TAG, "onCreate: " + activityComponent.theToaster().hashCode());
            Log.d(TAG, "onCreate: " + activityComponent.theToaster().hashCode());
            Log.d(TAG, "onCreate: " + activityComponent.toaster().hashCode());
            Log.d(TAG, "onCreate: " + activityComponent.toaster().hashCode());
        }
    }
    
    03-21 00:46:34.836 24014-24014/github.pedroneer.dagger2 D/toaster: onCreate: 1028556617
    03-21 00:46:34.836 24014-24014/github.pedroneer.dagger2 D/toaster: onCreate: 1028556617
    03-21 00:46:34.836 24014-24014/github.pedroneer.dagger2 D/toaster: onCreate: 857606222
    03-21 00:46:34.836 24014-24014/github.pedroneer.dagger2 D/toaster: onCreate: 614825327
    

    答案很明显,我们定义了PerActivity中的custom修饰的Toaster每次都是唯一的,而the修饰的则每次创建一个对象。这就是作用域及无作用域的区别。

    总结一下,当我们为一个组件打上标签作用域,那么这个组件的生命周期内,模块内的依赖也就随着组件的生命周期消亡而消亡,如果模块内存在提供作用域的Provider,而使用这个模块的组件不标注该作用域,则编译报错。Provider中提供的方法在同一模块内每次调用都会初始化,而标明了作用域的则不会。

    二.绑定类型

    这个上面的例子已经用过了,使用方法和RoboGuice相同,Dagger2也增加了Qualifier的概念,即可以自定义注解标示组件提供需要的注入类型。这里不做赘述。

    三.懒加载

    Dagger2支持Lazy Load,即在我们真正使用对象的时候才回去初始化。

    public class MainActivity extends BaseActivity {
    
        @Inject
        @Named("the")
        Lazy<Toaster> toasterLazy;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            if (something()) {
                toasterLazy.get().longToast("hello");
            }
        }
    
        private boolean something() {
            return new Random().nextBoolean();
        }
    }
    

    这样大大的提高了我们的效率,比如在BaseActivity中注入了多种依赖,如果不希望创建的时候即初始化,可以使用懒加载,只有在使用的时候初始化。

  • 相关阅读:
    PAT (Advanced Level) 1114. Family Property (25)
    PAT (Advanced Level) 1113. Integer Set Partition (25)
    PAT (Advanced Level) 1112. Stucked Keyboard (20)
    PAT (Advanced Level) 1111. Online Map (30)
    PAT (Advanced Level) 1110. Complete Binary Tree (25)
    PAT (Advanced Level) 1109. Group Photo (25)
    PAT (Advanced Level) 1108. Finding Average (20)
    PAT (Advanced Level) 1107. Social Clusters (30)
    PAT (Advanced Level) 1106. Lowest Price in Supply Chain (25)
    PAT (Advanced Level) 1105. Spiral Matrix (25)
  • 原文地址:https://www.cnblogs.com/pedro-neer/p/5307964.html
Copyright © 2011-2022 走看看