• 解锁Dagger2使用姿势(二) 之带你理解@Scope


    关于Dagger2使用的基础如果你还不了解,可以参考我的上一篇文章解锁Dagger2使用姿势(一),这有助于你理解本篇文章。


    OK,我们在上篇文章介绍另外Dagger2使用过程中四个基本的注解,分别是@Module、@Provides、@Inject以及@Component。今天我想来说说Dagger2中另外一个注解,那就是@Scope注解。看网上的资料,大家基本上都知道@Scope是用来给依赖划定作用域的,那我今天就来来说说这个作用域的问题。

    首先Dagger2中有一个现成的作用域注解,那就是@Singleton,其实这个@Singleton还是由Java提供的。那么这个注解的作用域就是让我们的依赖成为单例模式。比如下面一个例子:假设我有一个用户对象,如下:

    public class User {
    
    	....
    	....
    	
        @Inject
        public User() {
        }
    
    	....
    	....
    	
    }

    我这里暂时先用@Inject来注解这个用户对象,避免使用Module,然后我需要一个Component来注入这个User对象到我的Activity中,我的Component如下:

    @Component
    public interface ActivityComponent {
        void inject(MainActivity activity);
    }

    OK,然后我在我的MainActivity中初始化User对象,并将其地址显示出来:

    public class MainActivity extends AppCompatActivity {
    
        @Inject
        User user;
        @Inject
        User user2;
        private TextView tv;
        private TextView tv2;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            DaggerActivityComponent.builder().build().inject(this);
            tv = ((TextView) findViewById(R.id.tv));
            tv2 = ((TextView) findViewById(R.id.tv2));
            tv.setText(user.toString());
            tv2.setText(user2.toString());
        }
    }

    显示结果如下:

    OK ,大家看到这完全是两个不同的对象,两个对象的引用地址完全不一样。那如果我想让User变为一个单例模式该怎么办呢?其实很简单,添加上@Singleton注解就可以了,在哪里添加呢?两个地方:

    1.给User类添加上@Singleton注解:

    @Singleton
    public class User {
    
    	....
    	....
    	
        @Inject
        public User() {
        }
    
    	....
    	....
    	
    }

    2.给ActivityComponent添加上@Singleton注解

    @Singleton
    @Component
    public interface ActivityComponent {
        void inject(MainActivity activity);
    }

    如此之后我再运行,结果如下:

    OK,这个时候User对象就会以单例形式存在于我的App中了。OK,那如果我的项目中有Module,又该如何使我的User对象单例呢?

    很简单,在Module中提供User对象,提供User对象的方法需要有单例注解:

    @Module
    public class UserModule {
        @Provides
        @Singleton
        User providesUser() {
            return new User();
        }
    }

    这个时候User对象上的注解就都可以去掉了,然后稍微修改一下ActivityComponent,如下:

    @Singleton
    @Component(modules = UserModule.class)
    public interface ActivityComponent {
        void inject(MainActivity activity);
    }

    然后MainActivity中初始化的代码也要稍微修改一下下:

    DaggerActivityComponent.builder().userModule(new UserModule()).build().inject(this);

    然后再运行,依然是单例模式。

    OK,那我们知道@Singleton注解实际上实现的是一个全局单例模式,在实际开发中我们可能还需要一种局部单例的控件(这个应该是更常用),比如说我们有三个Activity,MainActivity,BActivity和CActivity,我们想让MainActivity和BActivity共享同一个实例,而让CActivity获取另外一个实例,这又该怎么实现呢?在Dagger2中,我们可以通过自定义Scope来实现局部单例。爽歪歪吧!OK,那就动手吧:

    首先让我们先来定义一个局部作用域:

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

    然后在我们的UserModule和ActivityComponent中应用该局部作用域:

    @Module
    public class UserModule {
        @Provides
        @UserScope
        User providesUser() {
            return new User();
        }
    }

    @UserScope
    @Component(modules = UserModule.class)
    public interface ActivityComponent {
        void inject(MainActivity activity);
    
        void inject(BActivity activity);
    }

    请大家注意,我的ActivityComponent作为一个注入器只可以向MainActivity和BActivity两个Activity中注入依赖,不可以向CActivity中注入依赖。最后,要让该局部作用域产生单例效果,需要我们在自定义的Appliation类中来初始化这个Component,如下:

    public class MyApp extends Application {
        ActivityComponent activityComponent;
        @Override
        public void onCreate() {
            super.onCreate();
            activityComponent = DaggerActivityComponent.builder().userModule(new UserModule()).build();
        }
    
        ActivityComponent getActivityComponent(){
            return activityComponent;
        }
    }
    接下来我们在MainActivity和BActivity中注入依赖,MainActivity如下:

        @Inject
        User user;
        @Inject
        User user2;
        private TextView tv;
        private TextView tv2;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    //        DaggerActivityComponent.builder().userModule(new UserModule()).build().inject(this);
            ((MyApp) getApplication()).getActivityComponent().inject(this);
            tv = ((TextView) findViewById(R.id.tv));
            tv2 = ((TextView) findViewById(R.id.tv2));
            tv.setText(user.toString());
            tv2.setText(user2.toString());
        }

    BActivity如下:

        @Inject
        User user;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_b);
            ((MyApp) getApplication()).getActivityComponent().inject(this);
            TextView tv = (TextView) findViewById(R.id.tv);
            tv.setText(user.toString());
        }

    那么如果我还想在CActivity中使用User对象该怎么办呢?再来一个CUserModule和CActivityComponent呗!

    CUserModule如下:

    @Module
    public class CUserModule {
        @Provides
        User providesUser() {
            return new User();
        }
    }

    这里我没有再注明单例了哦!

    CActivityComponent如下:

    @Component(modules = CUserModule.class)
    public interface CActivityComponent {
        void inject(CActivity activity);
    }

    在CActivity中注入依赖:

        @Inject
        User user;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_c);
            DaggerCActivityComponent.builder().cUserModule(new CUserModule()).build().inject(this);
            TextView tv = (TextView) findViewById(R.id.tv);
            tv.setText(user.toString());
        }

    运行结果如下:


    大家看到,MainActivity和BActivity是同一个实例,而CActivity则是另外一个实例。

    那么可能会有小伙伴问@UserScope在这里到底起了什么作用?我引用网上一段话:

    以下文字来源:http://blog.csdn.net/u012943767/article/details/51941872


    Scope的使用,如何实现单例?
    
    这个迷之Scope也是有点难以理解,我们在哪里使用到了Scope呢。在我们的AppComponent中添加了一个注解为@Singleton,@Singleton就是一个Scope,据说可以实现单例哟。。。难道这样就实现了单例模式?我刚刚开始是这样理解的。直到仔细的看了几遍这篇文章我才知道并不是这样的。
    
    事实上@Sinleton中并没有创建单例的能力,那么AppComponent中提供的依赖注入是如何实现单例的呢。其实这个原理很贱单。
    
    首先Module提供了创建实例的方法,接着AppComponent中对Module进行管理,最后AppComponent在自定义Applicaiton中被实例化了一次。
    
    这个实例化了一次是最重要的呀。仅仅被实例化了一次,那不就是单例么。就是这么简单呀。
    
    可能有些童靴当时就不乐意了,那既然这样都已经实现了单例,那么这个@Singltop还要来何用?不是多此一举吗。
    
    其实@Singletop还有有一些作用的,首先一方面能让你直面的了解到这是一个单例,其次这个@Singletop能够更好的管理Modlue和Component之间的关系。
    
    Dagger2需要保证Component和Module是匹配的,就需要用到这个注解。



    OK,这就是Dagger2中@Scope注解的使用。后面我再来介绍Component之间的依赖关系。


    以上。


    Demo下载http://download.csdn.net/detail/u012702547/9603997



  • 相关阅读:
    将Color的格式转变成颜色值
    F# 学习笔记 1 基础学习
    GridView 72般绝技
    前台直接读取Web.config中的值的方法
    根据属性名称 获取对象的属性值
    字符集与字符编码简介(转)
    一个WinForm程序配置信息的简单模型和维护工具——设计说明
    扩展DLL调用扩展DLL的LINK2001错误的解决办法之一
    CProfile : 读写私有INI配置文件
    日记:如何在MFC中使用Winsock2
  • 原文地址:https://www.cnblogs.com/qitian1/p/6461677.html
Copyright © 2020-2023  润新知