源码分享,如需转载,请注明作者: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<$class$> INSTANCE = new Singleton<$class$>() { @Override protected $class$ create() { return new $class$(); } }; private $class$() { } public static $class$ getInstance() { return INSTANCE.get(); }" 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 实现单例。