Android中的单例模式(java单例模式详解,Glide,EventBus,LayoutInfalter的源码单例模式详解)

一.单例模式

(1)单例模式介绍和定义

​ 大概意思是保证一个类在任何时候都只有一个实例在内存里,以static形式提供整个项目的访问。在Android系统中常用的地方有:创建一个SQLiteOpenHelper的数据库对象,应用每次启动都只会存在一个实例,也就是我们的application对象,这个时候就可以使用单例模式优化代码。

(一)饿汉式单例模式

/**
 * 饿汉式单例
 * 优点:不需要上锁,从性能角度看更好。
 * 缺点:一开始类加载就初始化好了对象,占用内存空间。
 */
public class Singleton {
    private final static Singleton mInstance = new Singleton();

    private Singleton() {

    }

    public static Singleton getInstance() {
        return mInstance;
    }
}

在Android上个人理解

在安卓系统加载的时候会调用application这个类,饿汉式单例模式适用于在启动的时候做一些初始化的操作,比如初始化Context。

(二)懒汉式单例模式

双重检查机制:防止多线程并发导致创建多个对象的问题,

对象创建的过程

1.申请内存空间。2.初始化。3.把地址赋值给引用,

引入一个概念:重排序,一般我们认为代码的执行顺序是按照我们的惯性思维,从上往下一句一句代码执行下去的。

​ 但是重排序可能会导致代码的执行顺序颠倒,导致逻辑上的错误,或者说不符合需求的逻辑。在上面我们说的对象创建的过程顺序是不一定的,也许是顺序执行1.申请内存空间。2.初始化。3.把地址赋值给引用这三个操作,也有可能顺序错乱执行,假设我们先1.申请内存空间,然后就执行3.把地址赋值给引用,最后执行2.初始化。举例 A a=new A();new操作在内存堆空间申请了空间,但是未初始化,就执行第三步的话,毫无疑问在对象还没初始化好里面的代码块,就赋值给引用去使用的话,会报错。

​ 此时就可以使用volatile关键字 ,保证在多线程并发操作的情况下,访问的是主内存中的数据信息,这样就不会因为线程在并发执行修改数据而导致获取不到最新数据信息的情况错误发生。

/**
 * 懒汉式单例
 * 优点:双重检查,volatile关键字可以阻止代码的重排序发生
 * 缺点:性能相对于饿汉式要低,因为使用了synchronized关键字,导致线程其如果没有类锁权限的话需要排队等待
 */
public class Singleton {
    private static volatile Singleton mInstance = null;

    private Singleton() {

    }

    public static Singleton getInstance() {
        //第一次检查 先判断对象是否为空
        if (mInstance == null) {
            /**
            	这里假设有两个线程A,B进入到这里,竞争这个类锁资源,假设A先竞争到这个锁的权限,
            	此时mInstance == null,所以将对象创建出来,A线程结束后,B线程获得锁的权限,假设没有
            	 if (mInstance == null),B线程进来的时候就会又创建一个对象,破坏了单一原则。
            */
            synchronized (Singleton.class) {
                if (mInstance == null) {
                    mInstance = new Singleton();
                }
            }
        }
        return mInstance;
    }
}

在Android开发中,我们经常会写一些工具类,需要其他地方来调用,此时我们封装工具类的时候,优先使用懒汉式,它可以避免提前加载,占用内存的资源。

(三)静态内部类实现单例模式

/**
 * 静态内部类单例
 * 优点:外部类加载的时候并不需要立即去加载内部类,内部类不被加载则不会实例化mInstance,不占内存资源,
 * 保证单例的唯一性,同时也延迟了单例的实例化。
 */
public class SingleTon {
    private SingleTon() {

    }

    private static class SingleTonHolder {
        private static SingleTon mInstance = new SingleTon();
    }

    public static SingleTon getInstance() {
        return SingleTonHolder.mInstance;
    }
}

静态内部类是实现单例模式的最好的一种形式,当SingleTon第一次被加载时,并不需要去加载它里面的内部类SingleTonHoler,只有当getInstance()方法第一次被调用时,才会去初始化mInstance,第一次调用getInstance()方法会导致虚拟机加载SingleTonHoler类。

二.android中常用框架的单例模式解析

(一)Glide源码分析

前言:Glide是一个性能非常强大的图片加载框架。

(1)Glide初始化及其简单使用。

Glide.with(this).load("").into(new ImageView(this));

首先Glide.with(this),最终返回的是RequestManager对象,本文重点描述单例模式,所以仅仅研究Glide单例模块部分的代码。

一开始我们调用with方法,接着我们调用了getRetriever(context)将所在的上下文对象传进去。

@NonNull
public static RequestManager with(@NonNull Context context) {
  return getRetriever(context).get(context);
}

来看我们的getRetriever(Context context)方法中,Glide.get(context)进入到get方法。


@NonNull
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
  // Context could be null for other reasons (ie the user passes in null), but in practice it will
  // only occur due to errors with the Fragment lifecycle.
  Preconditions.checkNotNull(
      context,
      "You cannot start a load on a not yet attached View or a Fragment where getActivity() "
          + "returns null (which usually occurs when getActivity() is called before the Fragment "
          + "is attached or after the Fragment is destroyed).");
  return Glide.get(context).getRequestManagerRetriever();
}

最终我们在这里实例化了我们的Glide单例对象,然后我们来具体分析下它是怎么实现的。很明显它使用的二次判空的双重检查机制,保证的对象的单一性质,不会因为多个线程的访问而导致创建多个对象,破坏了单例设计模式的单一性质。

private static volatile Glide glide;

第一次判断是为了验证是否创建对象,判断为了避免不必要的同步。
第二次判断是为了避免重复创建单例,因为可能会存在多个线程通过了第一次判断在等待锁,来创建新的实例对象。

/**
 * Get the singleton.
 *
 * @return the singleton
 */
@NonNull
public static Glide get(@NonNull Context context) {
  if (glide == null) {
    GeneratedAppGlideModule annotationGeneratedModule =
        getAnnotationGeneratedGlideModules(context.getApplicationContext());
    synchronized (Glide.class) {
      if (glide == null) {
        checkAndInitializeGlide(context, annotationGeneratedModule);
      }
    }
  }

  return glide;
}

我们继续往下看,glide的实际的初始化是在checkAndInitializeGlide这个函数里面执行,进去看看,initializeGlide这就是一个初始化的标识,往下走:

@GuardedBy("Glide.class")
private static void checkAndInitializeGlide(
    @NonNull Context context, @Nullable GeneratedAppGlideModule generatedAppGlideModule) {
  // In the thread running initGlide(), one or more classes may call Glide.get(context).
  // Without this check, those calls could trigger infinite recursion.
  if (isInitializing) {
    throw new IllegalStateException(
        "You cannot call Glide.get() in registerComponents(),"
            + " use the provided Glide instance instead");
  }
  isInitializing = true;
  initializeGlide(context, generatedAppGlideModule);
  isInitializing = false;
}

进到initializeGlide()函数里面去看,Glide glide = builder.build(applicationContext);看到这句代码则是构建了一个Glide对象,最后经过一系列操作Glide.glide = glide;将这个对象赋值给成员变量,自此Gldie单例创建对象分析结束。

  1. @GuardedBy("Glide.class")
    @SuppressWarnings("deprecation")
    private static void initializeGlide(
        @NonNull Context context,
        @NonNull GlideBuilder builder,
        @Nullable GeneratedAppGlideModule annotationGeneratedModule) {
      Context applicationContext = context.getApplicationContext();
      List<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();
      if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
        manifestModules = new ManifestParser(applicationContext).parse();
      }
    
      if (annotationGeneratedModule != null
          && !annotationGeneratedModule.getExcludedModuleClasses().isEmpty()) {
        Set<Class<?>> excludedModuleClasses = annotationGeneratedModule.getExcludedModuleClasses();
        Iterator<com.bumptech.glide.module.GlideModule> iterator = manifestModules.iterator();
        while (iterator.hasNext()) {
          com.bumptech.glide.module.GlideModule current = iterator.next();
          if (!excludedModuleClasses.contains(current.getClass())) {
            continue;
          }
          if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "AppGlideModule excludes manifest GlideModule: " + current);
          }
          iterator.remove();
        }
      }
    
      if (Log.isLoggable(TAG, Log.DEBUG)) {
        for (com.bumptech.glide.module.GlideModule glideModule : manifestModules) {
          Log.d(TAG, "Discovered GlideModule from manifest: " + glideModule.getClass());
        }
      }
    
      RequestManagerRetriever.RequestManagerFactory factory =
          annotationGeneratedModule != null
              ? annotationGeneratedModule.getRequestManagerFactory()
              : null;
      builder.setRequestManagerFactory(factory);
      for (com.bumptech.glide.module.GlideModule module : manifestModules) {
        module.applyOptions(applicationContext, builder);
      }
      if (annotationGeneratedModule != null) {
        annotationGeneratedModule.applyOptions(applicationContext, builder);
      }
      Glide glide = builder.build(applicationContext);
      for (com.bumptech.glide.module.GlideModule module : manifestModules) {
        try {
          module.registerComponents(applicationContext, glide, glide.registry);
        } catch (AbstractMethodError e) {
          throw new IllegalStateException(
              "Attempting to register a Glide v3 module. If you see this, you or one of your"
                  + " dependencies may be including Glide v3 even though you're using Glide v4."
                  + " You'll need to find and remove (or update) the offending dependency."
                  + " The v3 module name is: "
                  + module.getClass().getName(),
              e);
        }
      }
      if (annotationGeneratedModule != null) {
        annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
      }
      applicationContext.registerComponentCallbacks(glide);
      Glide.glide = glide;
    }
    

(二)EventBus源码分析

主要还是看它使用单例模式创建对象的部分代码,如下,也是采用二次判空,双重检查的机制。

static volatile EventBus defaultInstance;
/** Convenience singleton for apps using a process-wide EventBus instance. */
public static EventBus getDefault() {
    if (defaultInstance == null) {
        synchronized (EventBus.class) {
            if (defaultInstance == null) {
                defaultInstance = new EventBus();
            }
        }
    }
    return defaultInstance;
}

(三)LayoutInfalter源码分析

在Android中我们写RecyclerView的适配器时就会用到LayoutInfalter,使用LayoutInflater.from(parent.getContext())来获取我们的LayoutInflater服务给我们应用层,然后我们看一下from方法,

public class RvAdapter extends RecyclerView.Adapter<RvViewHolder> {
    ...
    @NonNull
    @Override
    public RvViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.rv_item,parent,false);
        return new RvViewHolder(itemView);
    }
    ...
}

进入from方法,看代码可以知道,LayoutInflater对象是由传进来的context调用getSystemService方法来获取的,这个方法从名字上也可以看出来是获取系统服务的意思,所以最终的初始化是context的getSystemService方法来做的。

/**
 * Obtains the LayoutInflater from the given context.
 */
public static LayoutInflater from(Context context) {
  	LayoutInflater LayoutInflater =
              (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  	if (LayoutInflater == null) {
            throw new AssertionError("LayoutInflater not found.");
  	}
	return LayoutInflater;
}

因为我们传进来的Context大多都是依附于Activity,所以我们拿Activity举例,继承的是父类ContextThemeWrapper的getSystemService方法,仔细看mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);这行代码,getBaseContext()方法会返回一个Context的实例对象。

往下走最终调用了父类ContextThemeWrapper的attachBaseContext方法,将ContextImpl对象赋值给mBase(这里暂时不深入探究,知道是这样即可)。

@Override
public Object getSystemService(String name) {
    if (LAYOUT_INFLATER_SERVICE.equals(name)) {
        if (mInflater == null) {
            mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
        }
        return mInflater;
    }
    return getBaseContext().getSystemService(name);
}

接下来我们看一下ContextImpl的getSystemService()方法的实现,return SystemServiceRegistry.getSystemService(this, name);我们直接看到最后一句,显然这里是返回一个对象,因为该方法的放回置接收类型是一个Object类型。继续往下走代码。

@Override
public Object getSystemService(String name) {
    if (vmIncorrectContextUseEnabled()) {
        // Check incorrect Context usage.
        if (WINDOW_SERVICE.equals(name) && !isUiContext()) {
            final String errorMessage = "Tried to access visual service "
                    + SystemServiceRegistry.getSystemServiceClassName(name)
                    + " from a non-visual Context:" + getOuterContext();
            final String message = "WindowManager should be accessed from Activity or other "
                    + "visual Context. Use an Activity or a Context created with "
                    + "Context#createWindowContext(int, Bundle), which are adjusted to "
                    + "the configuration and visual bounds of an area on screen.";
            final Exception exception = new IllegalAccessException(errorMessage);
            StrictMode.onIncorrectContextUsed(message, exception);
            Log.e(TAG, errorMessage + " " + message, exception);
        }
    }
    return SystemServiceRegistry.getSystemService(this, name);
}

我们进入到SystemServiceRegistry.getSystemService(this, name);这个类的方法里面看看,重点看这句代码final Object ret = fetcher.getService(ctx);通过传入一个ContextImpl的对象,调用createService创建一个service对象,缓存到列表中,下次再取时直接从缓存列表中拿。这样就保证了服务的单例。

/**
 * Gets a system service from a given context.
 * @hide
 */
public static Object getSystemService(ContextImpl ctx, String name) {
    if (name == null) {
        return null;
    }
    final ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
    if (fetcher == null) {
        if (sEnableServiceNotFoundWtf) {
            Slog.wtf(TAG, "Unknown manager requested: " + name);
        }
        return null;
    }

    final Object ret = fetcher.getService(ctx);
    if (sEnableServiceNotFoundWtf && ret == null) {
        // Some services do return null in certain situations, so don't do WTF for them.
        switch (name) {
            case Context.CONTENT_CAPTURE_MANAGER_SERVICE:
            case Context.APP_PREDICTION_SERVICE:
            case Context.INCREMENTAL_SERVICE:
            case Context.ETHERNET_SERVICE:
                return null;
        }
        Slog.wtf(TAG, "Manager wrapper not available: " + name);
        return null;
    }
    return ret;
}

由于对LayoutInfalter了解还不是很多,所以很多细节源码还需要再学习,研究,这里简单分析单例模式对象的生成。

总结

名称 优点 缺点
普通的单例模式 实现简单,操作简单,理解简单 多线程并发操作资源的时候不安全,会导致资源数据混乱
饿汉模式 线程安全 内存资源的消耗会相对多一些
懒汉模式 线程安全 需要上锁,线程资源需要同步排队等待执行,性能方面相对较低
静态内部类模式 线程安全、避免了对象的实例化操作,可通过外部类直接访问静态的内部类操作创建单一的实例对象。 暂无

你可能感兴趣的:(单例模式,java,android)