隐藏在 SDK 中的单例类模板

2,104 阅读3分钟

源码分享,如需转载,请注明作者:Yuloran (t.cn/EGU6c76)

前言

单例类写法,网上有诸多介绍,此处不再赘述。不过仍有一点需要注意一下:从编程规范角度来讲,单例类应当是不可继承和构造器私有的,即:

public final class ActivityMgrService
{
    private ActivityMgrService()
    {
    }
}

Kotlin 在这方面做的很好,对编程安全做了很多优化。比如,类默认不可继承,如果需要被继承,需显式使用 open 关键字。

单例模板

虽然单例写法很多,但是同一个项目不可能允许那么多的单例类写法同时存在。所以,我们需要一个单例模板。其实,Android SDK 早就为我们提供了这样一个模板,可能很多人不知道,因为它是 @hide 的。

Singleton 源码

/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.util;

/**
 * Singleton helper class for lazily initialization.
 *
 * Modeled after frameworks/base/include/utils/Singleton.h
 *
 * @hide
 */
public abstract class Singleton<T> {
    private T mInstance;

    protected abstract T create();

    public final T get() {
        synchronized (this) {
            if (mInstance == null) {
                mInstance = create();
            }
            return mInstance;
        }
    }
}

在 Android Studio 中双击 Shift,输入 Singleton,即可检索到此类。因为是 @hide,所以需要手动复制到自己的项目中。

使用示例

public final class ActivityMgrService
{
    private static final String TAG = "ActivityMgrService";

    private static final Singleton<ActivityMgrService> INSTANCE = new Singleton<ActivityMgrService>()
    {
        @Override
        protected ActivityMgrService create()
        {
            return new ActivityMgrService();
        }
    };

    private ActivityMgrService()
    {
    }

    public static ActivityMgrService getInstance()
    {
        return INSTANCE.get();
    }

    ...
}

ActivityMgrService 是笔者写的一个监控项目中所有 Activity 生命周期的工具类,对此类感兴趣可以点击链接自行获取。

Live Template

可以新建一个 Live Template 来一键生成以上代码:

1. 新建 Template Group

2. 新建 Template

3. 手动编写 Template

下面是笔者的单例生成模板:

private static final Singleton<$class$> INSTANCE = new Singleton<$class$>() {
    @Override
    protected $class$ create() {
        return new $class$();
    }
};

private $class$() {
}

public static $class$ getInstance() {
    return INSTANCE.get();
}

模板变量配置:

4. 导入 Template

也可以直接导入笔者的单例模板:

<template name="sigl" value="private static final Singleton&lt;$class$&gt; INSTANCE = new Singleton&lt;$class$&gt;() {&#10;    @Override&#10;    protected $class$ create() {&#10;        return new $class$();&#10;    }&#10;};&#10;&#10;private $class$() {&#10;}&#10;&#10;public static $class$ getInstance() {&#10;    return INSTANCE.get();&#10;}" description="singleton" toReformat="true" toShortenFQNames="true">
  <variable name="class" expression="className()" defaultValue="" alwaysStopAt="false" />
  <context>
    <option name="JAVA_CODE" value="true" />
  </context>
</template>

复制以上代码,在 Template Group 上右键粘贴即可:

单例模板扩展

SDK 源码提供的单例不带参数,所以我们可以自行扩展一个带参数的单例模板:

/*
 * Copyright (C) 2018 Yuloran(https://github.com/Yuloran)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.yuloran.lib_core.template;

/**
 * [带一个参数的单例模板类]
 * <p>
 * Author: Yuloran
 * Date Added: 2018/12/16 12:13
 *
 * @since 1.0.0
 */
public abstract class Singleton1<T, P>
{
    private T mInstance;

    protected abstract T create(P arg);

    public final T get(P arg)
    {
        synchronized (this)
        {
            if (mInstance == null)
            {
                mInstance = create(arg);
            }
            return mInstance;
        }
    }
}

用法与 Singleton 类似,不再介绍。

单例写法之 CAS

我们可以借助 AtomicReference 的 compareAndSet() 来实现单例:

package com.yuloran.lib_core.template;

import java.util.concurrent.atomic.AtomicReference;

/**
 * [CAS 实现的单例类]
 * <p>
 * Author: Yuloran
 * Date Added: 2019/1/3 12:13
 *
 * @since 1.0.0
 */
public final class SingletonCAS
{
    private static final AtomicReference<SingletonCAS> INSTANCE = new AtomicReference<>();

    private SingletonCAS()
    {
    }

    public static SingletonCAS getInstance()
    {
        for (; ; )
        {
            SingletonCAS instance = INSTANCE.get();

            if (instance != null)
            {
                return instance;
            }

            // 多线程并发访问时,此处可能创建多个实例
            instance = new SingletonCAS();

            if (INSTANCE.compareAndSet(null, instance))
            {
                return instance;
            }
        }
    }
}

这种写法可以保证单例,但是有个致命的问题:for 循环中可能创建多个实例!

结语

所以还是使用单例模板类比较好,即安全又省事。如果你是 Kotlin 开发者,你也可以使用 object 或 companion 实现单例。