文章目录
单例设计模式在Android开发实际应用场景解析–activity的管理
Android中实际场景
常用的场景都是一些特殊的类,比如,管理类,皮肤的管理,activity的管理。
1.1 介绍
客户端调用单例类。
思路:
- 构造函数私有化。
- 通过静态方法获取单例对象。客户端调用
- 多线程环境下确保对象只有一个。
- 反序列化不能重新构造新对象。
1.1.1 懒汉模式
声明一个静态对象,第一次调用就初始化。
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static synchronized Singleton getInstance(){
if (instance == null){
instance = new Singleton();
}
return instance;
}
}
我们加上synchronized关键字,这样就可以做到线程的同步,在多线程环境下保证单例。懒汉式在第一次调用的时候才会实例化,节约资源,缺点是同步方法的调用造成资源开销。
1.1.2 DCL单例
需要时才实例化单例,保证线程安全,并且没有同步锁开销。
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class){
if (instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
getInstance()方法中我们判空两次,第一次是避免每次调用都进行同步锁,第二次是在null的条件下创建实例对象。
分析:
假设A,B两个线程执行getInstance(),instance = new Singleton();这句代码会被翻译成多条汇编指令,
- 分配内存。
- 调用构造函数。
- 将引用指向内存空间。
在多线程的环境下,这三个步骤的执行顺序不一样会导致DCL失效,执行顺序有可能1,2,3,或者1,3,2。在3执行完,2没执行之前,切换到B线程,这时候线程A执行了3,instance已经非空,B线程获取instance已经非空,就会出错。
1.1.3 volatile关键字
- 防止重排序。
- 线程可见性–某一个线程改变了公用对象(变量),短时间内可能是不可见的,每一个线程都有自己的缓冲区,线程工作区,
public class Singleton {
private volatile static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class){
if (instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
1.1.4 静态内部类
第一次加载Singleton类不会实例化对象,第一次调用getInstance才会导致被初始化,第一次调用getInstance()导致SingletonHolder加载,可以保证线程安全,对象唯一,延迟实例化。
public class Singleton {
private Singleton() {
}
public static Singleton getInstance() {
return SingletonHolder.sInstance;
}
private static class SingletonHolder {
private static final Singleton sInstance = new Singleton();
}
}
1.1.5 容器单例模式
Android系统服务用的这种
public class Singleton {
private static Map<String, Object> mSingleton = new HashMap<>();
static {
mSingleton.put("activity_manager", new Singleton());
}
public static Object getService(String serviceName) {
return mSingleton.get(serviceName);
}
}
Android实际应用–Activity的管理
需求背景:当我们有很多个activity的时候,需要写一个管理类来操作它们的增删改查。
xml布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".activity.DebugActivity">
<TextView
android:onClick="click"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="text"
android:textSize="30sp" />
</LinearLayout>
ActivityManager管理类
public class ActivityManager {
private static ActivityManager mInstance;
private Stack<Activity> mActivities;
private ActivityManager() {
mActivities = new Stack<>();
}
public static ActivityManager getInstance() {
if (mInstance == null) {
synchronized (ActivityManager.class) {
if (mInstance == null) {
mInstance = new ActivityManager();
}
}
}
return mInstance;
}
public void attach(Activity activity) {
mActivities.add(activity);
}
public void detach(Activity detachActivity) {
for (Activity activity : mActivities) {
if (activity == detachActivity) {
mActivities.remove(activity);
}
}
}
public void finish(Activity finishActivity) {
for (Activity activity : mActivities) {
if (activity == finishActivity) {
mActivities.remove(activity);
activity.finish();
}
}
}
public void finish(Class<? extends Activity> finishClassActivity) {
for (Activity activity : mActivities) {
if (activity.getClass().getCanonicalName().equals(finishClassActivity.getCanonicalName())) {
mActivities.remove(activity);
activity.finish();
}
}
}
public Activity currentActivity() {
return mActivities.lastElement();
}
}
LoginActivity
public class LoginActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActivityManager.getInstance().attach(this);
setTitle("我是LoginActivity");
}
public void click(View view) {
Intent intent = new Intent(this, RegisterActivity.class);
startActivity(intent);
}
@Override
protected void onDestroy() {
super.onDestroy();
ActivityManager.getInstance().detach(this);
}
}
RegisterActivity
public class RegisterActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActivityManager.getInstance().attach(this);
setTitle("我是RegisterActivity");
}
@Override
protected void onDestroy() {
super.onDestroy();
ActivityManager.getInstance().detach(this);
}
public void click(View view) {
ActivityManager.getInstance().finish(this);
ActivityManager.getInstance().finish(LoginActivity.class);
}
}
DebugActivity
class DebugActivity : AppCompatActivity() {
private val TAG = javaClass.simpleName
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
ActivityManager.getInstance().attach(this)
title = "我是DebugActivity"
}
fun click(view: View) {
val intent = Intent(this, LoginActivity::class.java)
startActivity(intent)
}
override fun onDestroy() {
super.onDestroy()
ActivityManager.getInstance().detach(this)
}
}
不管以哪种形式实现单例模式,
它们的核心原理都是将构造函数私有化,
并且通过静态方法获取一个唯一的实例,
在这个获取的过程中须保证线程安全、
防止反序列化导致重新生成实例对象等问题。
选择哪种实现方式取决于项目本身,
如是否是复杂的并发环境、JDK 版本是否过低、单例对象的资源消耗等。