首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Kotlin入门(28)Application单例化

Kotlin入门(28)Application单例化

作者头像
aqi00
发布2019-01-18 15:57:47
2.1K0
发布2019-01-18 15:57:47
举报
文章被收录于专栏:老欧说安卓老欧说安卓

Application是Android的又一大组件,在App运行过程中,有且仅有一个Application对象贯穿应用的整个生命周期,所以适合在Application中保存应用运行时的全局变量。而开展该工作的基础,是必须获得Application对象的唯一实例,也就是将Application单例化。获取一个类的单例对象,需要运用程序设计中常见的单例模式,倘若通过Java编码实现单例化,想必早已是大家耳熟能详的了。下面便是个Application单例化的Java代码例子:

public class MainApplication extends Application {

    private static MainApplication mApp;
    
    public static MainApplication getInstance() {
        return mApp;
    }    @Override
    public void onCreate() {
        super.onCreate();
        mApp = this;
    }
}

从上可见这个单例模式的实现过程主要有三个步骤,说明如下:

1、在自定义的Application类内部声明一个该类的静态实例;

2、重写onCreate方法,把自身对象赋值给第一步声明的实例;

3、提供一个供外部调用的静态方法getInstance,该方法返回第一步声明的Application类实例;

不管是代码还是步骤,这个单例化的实现都还蛮简单的。同样的单例化过程通过Kotlin编码实现的话,静态属性和静态方法可利用伴生对象来实现,这样就形成了Kotlin单例化的第一种方式:手工声明属性的单例化,具体描述见下。

一、手工声明属性的单例化

该方式与Java的常见做法一致,也是手工声明自身类的静态实例,然后通过静态方法返回自身实例。与Java的不同之处在于:Kotlin引入了空安全机制,故而静态属性要声明为可空变量、然后获得实例时要在末尾加上双感叹号表示非空,当然也可事先将自身实例声明为延迟初始化属性。总之,两种声明手段都是为了确保一个目的,即Application类提供给外部访问的自身实例必须是非空的。

下面是手工单例化的Kotlin代码例子:

class MainApplication : Application() {

    override fun onCreate() {
        super.onCreate()
        instance = this
    }

    //单例化的第一种方式:声明一个简单的Application属性
    companion object {
        //情况一:声明可空的属性
        private var instance: MainApplication? = null
        fun instance() = instance!!
        //情况二:声明延迟初始化属性
        //private lateinit var instance: MainApplication
        //fun instance() = instance
    }
}

二、借助Delegates的委托属性单例化

第一种方式的单例化,虽然提供了两种属性的声明手段,但只是为了保证自身实例的非空性。如果仅仅是确保属性非空,其实Kotlin已经提供了一个系统工具进行自动校验,这个工具便是Delegates的notNull方法。该方法返回非空校验的行为,只要将指定属性的读写行为委托给这个非空校验行为,那么开发者就无需手工进行非空判断了。利用Delegates工具的属性代理功能,就构成了Kotlin的第二种单例化方式;有关委托属性和属性代理的介绍,可参见前面的博文《Kotlin入门(25)共享参数模板》。

下面是系统委托属性单例化的Kotlin代码例子:

class MainApplication : Application() {

    override fun onCreate() {
        super.onCreate()
        instance = this
    }

    //单例化的第二种方式:利用系统自带的Delegates生成委托属性
    companion object {
        private var instance: MainApplication by Delegates.notNull()
        fun instance() = instance
    }
}

第二种方式的委托属性单例化,在App代码中获取Application实例与第一种方式是一样的,都是调用“MainApplication.instance()”这个函数获得Application的自身实例。

三、自定义委托行为的单例化

前两种单例化都只完成了非空校验,还不是严格意义上的单例化。真正的单例化是有且仅有一次赋值操作,尽管前两种的单例化并未实现唯一赋值功能,但是在大多数场合已经够用了。可是作为孜孜不倦的开发者,务必要究根问底,到底能不能实现唯一赋值情况下的单例化。显然系统自带的Delegates工具没有提供大家期待的校验行为,于是开发者必须自己写一个能够校验赋值次数的行为类,目的是接管委托属性的读写行为。自定义接管行为的实现,前面的博文《Kotlin入门(25)共享参数模板》即已给出了Preference<T>的完整源码,其中关键是重写了读方法getValue和写方法setValue,因此在这里可借鉴Preference<T>完成自定义的委托行为编码。

下面是自定义委托行为的单例化代码:

class MainApplication : Application() {

    override fun onCreate() {
        super.onCreate()
        instance = this
    }

    //单例化的第三种方式:自定义一个非空且只能一次性赋值的委托属性
    companion object {
        private var instance: MainApplication by NotNullSingleValueVar()
        fun instance() = instance
    }

    //定义一个属性管理类,进行非空和重复赋值的判断
    private class NotNullSingleValueVar<T>() : ReadWriteProperty<Any?, T> {
        private var value: T? = null
        override fun getValue(thisRef: Any?, property: KProperty<*>): T {
            return value ?: throw IllegalStateException("application not initialized")
        }

        override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
            this.value = if (this.value == null) value
            else throw IllegalStateException("application already initialized")
        }
    }
}

由上述代码看到,自定义的委托行为在getValue方法中进行非空校验,在setValue方法中进行重复赋值的校验,从而按照要求接管了委托属性的读写行为。

点此查看Kotlin入门教程的完整目录

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年10月23日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、手工声明属性的单例化
  • 二、借助Delegates的委托属性单例化
  • 三、自定义委托行为的单例化
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档