美文网首页
Android单例的使用

Android单例的使用

作者: xqiiitan | 来源:发表于2024-07-11 10:23 被阅读0次

Android单例。

推荐使用静态内部内实现单例或加了Volatile关键字的双重检查单例

使用容器实现单例模式

// 在程序的初始,将多种单例模式注入到一个统一的管理类中,在使用时根据key获取对应类型的对象。
public class SingletonManager { 
   // 使用HashMap作为缓存容器
  private static Map<String, Object> objMap = new HashMap<String,Object>();
  private Singleton() {}
  public static void registerService(String key, Objectinstance) {
    if (!objMap.containsKey(key) ) {
      objMap.put(key, instance); //第一次是存入Map
    }
  }
  public static Object getService(String key) {
    return objMap.get(key); //返回与key相对应的对象
  }
}

LayoutInflater的单例模式实现

在日常开发中,我们经常使用系统提供的服务,如WindowManagerService,PackageManagerService,ActivityManagerService等,
但是我们最经常使用的一定少不了LayoutInflater,这些服务会在合适的时候以单例的形式注册在系统中,
我们需要的时候只需要通过context.getSystemService(String serviceName)方法获取即可。

LayoutInflater mInflater = LayoutInflater.from(this);
1.通过LayoutInflater.from(context)来获取LayoutInflater服务

LayoutInflater mInflater = LayoutInflater.from(this);
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;
}

2.context.getSystemService是怎么工作的,context的实现类是ContextImpl类,点进去看一下

// ContextImpl用来缓存已经创建的服务实例
final Object[] mServiceCache = SystemServiceRegistry.createServiceCache();
@Override
public Object getSystemService(String name) {
    return SystemServiceRegistry.getSystemService(this, name);
}

3.SystemServiceRegistry类中

// 容器类
private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
        new HashMap<String, ServiceFetcher<?>>();
/**
 * Gets a system service from a given context.
 */
public static Object getSystemService(ContextImpl ctx, String name) {
    ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
    return fetcher != null ? fetcher.getService(ctx) : null;
}
/**
 * Statically registers a system service with the context.
 * This method must be called during static initialization only.
 */
private static <T> void registerService(String serviceName, Class<T> serviceClass,
        ServiceFetcher<T> serviceFetcher) {
    SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
    SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
}

5.服务都是在什么时候注册的?

static {
    registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
        new CachedServiceFetcher<LayoutInflater>() {
        @Override
        public LayoutInflater createService(ContextImpl ctx) {
            return new PhoneLayoutInflater(ctx.getOuterContext());
        }});
    // 我们使用的ActivityManager在这注册
    registerService(Context.ACTIVITY_SERVICE, ActivityManager.class,
            new CachedServiceFetcher<ActivityManager>() {
        @Override
        public ActivityManager createService(ContextImpl ctx) {
            return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
        }});
    // 我们使用的AlarmManager在这注册
    registerService(Context.ALARM_SERVICE, AlarmManager.class,
            new CachedServiceFetcher<AlarmManager>() {
        @Override
        public AlarmManager createService(ContextImpl ctx) {
            IBinder b = ServiceManager.getService(Context.ALARM_SERVICE);
            IAlarmManager service = IAlarmManager.Stub.asInterface(b);
            return new AlarmManager(service, ctx);
        }});
}
  • 很明显,这是在一个静态的代码块进行注册服务,第一次加载该类的时候执行,并且只执行一次,保证实例的唯一性
  • 从这个过程中可以看出,系统将服务以键值对的形式存储在HashMap中,用户使用时只需要获取具体的服务对象,
    第一次获取时,调用getSystemService来获取具体的对象,
    在第一次调用时,会调用registerService通过map将对象缓存在一个列表中,
    下次再用时直接从容器中取出来就可以。避免重复创建对象,从而达到单例的效果。减少了资源消耗。
  • 在Android源码中,APP启动的时候,虚拟机第一次加载该类时会注册各种ServiceFetcher,比如LayoutInflater Service。
    将这些服务以键值对的形式存储在一个HashMap中,用户使用时只需要根据key来获取到对应的ServiceFetcher,
    然后通过ServiceFetcher对象的getService函数获取具体的服务对象。
    当第一次获取时,会调用ServiceFetcher的createService函数创建服务对象,然后将该对象缓存到一个列表中,
    下次再取时直接从缓存中获取,避免重复创建对象,从而达到单例的效果。Android中的系统核心服务以单例形式存在,减少了资源消耗。

分析下getService流程如下:

首先从ContextImpl缓存数组中获取对应的实例。
如果实例存在,直接返回实例对象;否则创建实例,并加入ContextImpl缓存数组中。
CachedServiceFetcher的实现了保证了,实例对象只在首次获取时才会被初始化,否则就返回已经缓存的对象,节省了系统资源。

综合分析我们得出如下结论:

  • 我们常用的一些系统Service是通过SystemServiceRegistry进行管理的。
  • 系统加载SystemServiceRegistry类时,通过静态块将各种服务类存储在
  • SYSTEM_SERVICE_FETCHERS(HashMap<ServiceName, ServiceFetcher>)中,每一个具体的服务类都对应一个ServiceFetcher。
  • 使用时从HashMap中获取ServiceFetcher,并从中获取需要的实例,获取的实例被缓存在ContextImpl中备用。
  • CachedServiceFetcher负责创建具体的实例,并将实例缓存到ContextImpl的缓存数组中。

涉及单例模式的几个要点:

  • SystemServiceRegistry使用HashMap管理ServiceFetcher。
  • ServiceFetcher保证实例只创建一次,且通过使用synchronized机制保证多线程安全。
  • 加入缓存机制,保证实例只会被创建一次。

EventBus(主要是使用双重检查DCL)

这样的话它的资源利用率会很高,并且第一次执行的时候,是单例对象才会被实例化,但是第一次加载的时候会稍慢,可以被接受.

static volatile EventBus defaultInstance;
public static EventBus getDefault() {
    if (defaultInstance == null) {
        synchronized (EventBus.class) {
            if (defaultInstance == null) {
                defaultInstance = new EventBus();
            }
        }
    }
    return defaultInstance;
}

ImageLoader图片加载框架

ImageLoader.getInstance();// 在自己的Application中创建全局实例
.....
//getInstance() 执行的源码
public static ImageLoader getInstance() {
    if(instance == null) {//双重校验DCL单例模式
        Class var0 = ImageLoader.class;
        synchronized(ImageLoader.class) {//同步代码块
            if(instance == null) {
                instance = new ImageLoader();//创建一个新的实例
            }
        }
    }
    return instance;//返回一个实例
}

Glide源码分析--单例。

Glide.with(this).load("").into(new ImageView(this));
public static RequestManager with(@NonNull Context context) {
  return getRetriever(context).get(context); // 传入上下文
}
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
  return Glide.get(context).getRequestManagerRetriever();
}

// Glide单例对象,然后我们来具体分析下它是怎么实现的。很明显它使用的二次判空的双重检查机制,保证的对象的单一性质,不会因为多个线程的访问而导致创建多个对象,破坏了单例设计模式的单一性质。
private static volatile Glide glide;
//第一次判断是为了验证是否创建对象,判断为了避免不必要的同步。
//第二次判断是为了避免重复创建单例,因为可能会存在多个线程通过了第一次判断在等待锁,来创建新的实例对象。
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;
}

@GuardedBy("Glide.class")
private static void checkAndInitializeGlide(
    @NonNull Context context, @Nullable GeneratedAppGlideModule generatedAppGlideModule) {
  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;
将这个对象赋值给成员变量,自此Glide单例创建对象分析结束。

@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; // 赋值。
}

相关文章

网友评论

      本文标题:Android单例的使用

      本文链接:https://www.haomeiwen.com/subject/dxcacjtx.html