《Android 源码设计模式解析与实战》——第2章,第2.7节Android源码中的单例模式

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介:

本节书摘来自异步社区《Android 源码设计模式解析与实战》一书中的第2章,第2.7节Android源码中的单例模式,作者 何红辉 , 关爱民,更多章节内容可以访问云栖社区“异步社区”公众号查看

2.7 Android源码中的单例模式
在Android系统中,我们经常会通过Context获取系统级别的服务,如WindowsManagerService、ActivityManagerService等,更常用的是一个LayoutInflater的类,这些服务会在合适的时候以单例的形式注册在系统中,在我们需要的时候就通过Context的getSystemService(String name)获取。我们以LayoutInflater为例来说明,平时我们使用LayoutInflater较为常见的地方是在ListView的getView方法中:

@Override
public View getView(int position, View convertView, ViewGroup parent)
  View itemView = null;
  if (convertView == null) {
    itemView = LayoutInflater.from(mContext).inflate(mLayoutId, null);
    // 代码省略
  } else {
    // 代码省略
  }
  // 代码省略
  return itemView;
}
通常我们使用LayoutInflater.from(Context)来获取LayoutInflater服务,下面看看LayoutInflater.from (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;
}
可以看到from(Context)函数内部调用的是Context类的getSystemService(String key)方法,我们跟踪到Context类看到,该类是抽象类:

public abstract class Context {
  // 省略
}

getView中使用的Context对象的具体实现类是什么呢?其实在Application、Activity、Service中都会存在一个Context对象,即Context的总个数为Activity个数 + Service个数 + 1。而ListView通常都是显示在Activity中,那么我们就以Activity中的Context来分析。

我们知道,一个Activity的入口是ActivityThread的main函数,在main函数中创建一个新的ActivityThread对象,并且启动消息循环(UI线程),创建新的Activity、新的Context对象,然后将该Context对象传递给Activity。下面看看ActivityThread源代码:

public static void main(String[] args) {
// 代码省略
    Process.setArgV0("<pre-initialized>");
    // 主线程消息循环
    Looper.prepareMainLooper();
    // 创建ActivityThread对象
    ActivityThread thread = new ActivityThread();
    thread.attach(false);

    if (sMainThreadHandler == null) {
      sMainThreadHandler = thread.getHandler();
    }

    AsyncTask.init();
    // 代码省略
    Looper.loop();
  }

  private void attach(boolean system) {
    sThreadLocal.set(this);
    mSystemThread = system;
    // 不是系统应用的情况
    if (!system) {
      ViewRootImpl.addFirstDrawHandler(new Runnable() {
        public void run() {
          ensureJitEnabled();
        }
      });

      android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",UserHandle.myUserId());
      RuntimeInit.setApplicationObject(mAppThread.asBinder());
      IActivityManager mgr = ActivityManagerNative.getDefault();
      try {
        // 关联mAppThread
        mgr.attachApplication(mAppThread);
      } catch (RemoteException ex) {
        // 省略
      }
    } else {
        // 省略
    }
}  

在main方法中,我们创建一个ActivityThread对象后,调用了其attach函数,并且参数为false。在attach函数中,参数为false的情况下(即非系统应用),会通过Binder机制与ActivityManager Service通信,并且最终调用handleLaunchActivity函数,我们看看该函数的实现:

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    // 代码省略
    Activity a = performLaunchActivity(r, customIntent);
    // 代码省略
  }

   private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    // 代码省略
    Activity activity = null;
    try {
      java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
      activity = mInstrumentation.newActivity(     // 1. 创建Activity
      cl, component.getClassName(), r.intent);
     // 代码省略
    } catch (Exception e) {
     // 省略
    }

    try {
    // 创建Application对象
      Application app = r.packageInfo.makeApplication(false, mInstrumentation);
      if (activity != null) {
        Context appContext = createBaseContextForActivity(r, activity);  
        // 2. 获取Context对象
        CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
        Configuration config = new Configuration(mCompatConfiguration);
        // 3. 将appContext等对象attach到activity中
        activity.attach(appContext, this, getInstrumentation(), r.token,
        r.ident, app, r.intent, r.activityInfo, title, r.parent,
        r.embeddedID, r.lastNonConfigurationInstances, config);

        // 代码省略
        // 4. 调用Activity的onCreate方法
        mInstrumentation.callActivityOnCreate(activity, r.state);
        // 代码省略
    } catch (SuperNotCalledException e) {
      throw e;
    } catch (Exception e) {
      // 代码省略
    }

    return activity;
  }
  private Context createBaseContextForActivity(ActivityClientRecord r,
      final Activity activity) {
    // 5. 创建Context对象, 可以看到实现类是ContextImpl
 ContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, r.token);
    appContext.setOuterContext(activity);
    Context baseContext = appContext;
    // 代码省略
    return baseContext;
  }

通过上面1~5注释处的代码分析可以知道,Context的实现类为ComtextImpl。我们继续跟踪ContextImpl类:

class ContextImpl extends Context {

// 代码省略
// ServiceFetcher通过getService获取服务对象
   static class ServiceFetcher {
    int mContextCacheIndex = -1;

    // 获取系统服务
    public Object getService(ContextImpl ctx) {
      ArrayList<Object> cache = ctx.mServiceCache;
      Object service;
      synchronized (cache) {
        if (cache.size() == 0) {
          for (int i = 0; i < sNextPerContextServiceCacheIndex; i++) {
            cache.add(null);
          }
        } else {
          service = cache.get(mContextCacheIndex); // 从缓存中获取Service对象
          if (service != null) {
            return service;
          }
        }
        service = createService(ctx);
        cache.set(mContextCacheIndex, service);
        return service;
      }
    }

    /**
     * 子类覆写该方法用以创建服务对象
     */
    public Object createService(ContextImpl ctx) {
      throw new RuntimeException("Not implemented");
    }
  }

  // 1. Service容器
  private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP =
      new HashMap<String, ServiceFetcher>();

  private static int sNextPerContextServiceCacheIndex = 0;
  // 2. 注册服务器
  private static void registerService(String serviceName, ServiceFetcher fetcher) {
    if (!(fetcher instanceof StaticServiceFetcher)) {
      fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
    }
    SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
  }

  // 3. 静态语句块, 第一次加载该类时执行 ( 只执行一次, 保证实例的唯一性 )
  static {
    // 代码省略
    // 注册LayoutInflater service
    registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {
        public Object createService(ContextImpl ctx) {
          return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
        }});
    // 代码省略
  }

  // 4. 根据key获取对应的服务 
  @Override
  public Object getSystemService(String name) {
    // 根据name来获取服务
    ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
    return fetcher == null ? null : fetcher.getService(this);
  }
  // 代码省略
}

从ContextImpl类的部分代码中可以看到,在虚拟机第一次加载该类时会注册各种ServiceFatcher,其中就包含了LayoutInflater Service。将这些服务以键值对的形式存储在一个HashMap中,用户使用时只需要根据key来获取到对应的ServiceFetcher,然后通过ServiceFetcher对象的getService函数来获取具体的服务对象。当第一次获取时,会调用ServiceFetcher的createService函数创建服务对象,然后将该对象缓存到一个列表中,下次再取时直接从缓存中获取,避免重复创建对象,从而达到单例的效果。这种模式就是小节中通过容器的单例模式实现方式,系统核心服务以单例形式存在,减少了资源消耗。

相关文章
|
2月前
|
Java 开发工具 Android开发
Android与iOS开发环境搭建全解析####
本文深入探讨了Android与iOS两大移动操作系统的开发环境搭建流程,旨在为初学者及有一定基础的开发者提供详尽指南。我们将从开发工具的选择、环境配置到第一个简单应用的创建,一步步引导读者步入移动应用开发的殿堂。无论你是Android Studio的新手还是Xcode的探索者,本文都将为你扫清开发道路上的障碍,助你快速上手并享受跨平台移动开发的乐趣。 ####
|
7天前
|
设计模式 缓存 应用服务中间件
「全网最细 + 实战源码案例」设计模式——外观模式
外观模式(Facade Pattern)是一种结构型设计模式,旨在为复杂的子系统提供一个统一且简化的接口。通过封装多个子系统的复杂性,外观模式使外部调用更加简单、易用。例如,在智能家居系统中,外观类可以同时控制空调、灯光和电视的开关,而用户只需发出一个指令即可。
110 69
|
6天前
|
设计模式 数据安全/隐私保护
Next.js 实战 (七):浅谈 Layout 布局的嵌套设计模式
这篇文章介绍了在Next.js框架下,如何处理中后台管理系统中特殊页面(如登录页)不包裹根布局(RootLayout)的问题。作者指出Next.js的设计理念是通过布局的嵌套来创建复杂的页面结构,这虽然保持了代码的整洁和可维护性,但对于特殊页面来说,却造成了不必要的布局包裹。文章提出了一个解决方案,即通过判断页面的skipGlobalLayout属性来决定是否包含RootLayout,从而实现特殊页面不包裹根布局的目标。
50 33
|
20天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
20天前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
|
20天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
20天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是"将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。创建型模式分为5种:单例模式、工厂方法模式抽象工厂式、原型模式、建造者模式。
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
20天前
|
设计模式 Java 程序员
【23种设计模式·全精解析 | 概述篇】设计模式概述、UML图、软件设计原则
本系列文章聚焦于面向对象软件设计中的设计模式,旨在帮助开发人员掌握23种经典设计模式及其应用。内容分为三大部分:第一部分介绍设计模式的概念、UML图和软件设计原则;第二部分详细讲解创建型、结构型和行为型模式,并配以代码示例;第三部分通过自定义Spring的IOC功能综合案例,展示如何将常用设计模式应用于实际项目中。通过学习这些内容,读者可以提升编程能力,提高代码的可维护性和复用性。
【23种设计模式·全精解析 | 概述篇】设计模式概述、UML图、软件设计原则
|
1月前
|
设计模式 存储 前端开发
前端必须掌握的设计模式——单例模式
单例模式是一种简单的创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点。适用于窗口对象、登录弹窗等场景,优点包括易于维护、访问和低消耗,但也有安全隐患、可能形成巨石对象及扩展性差等缺点。文中展示了JavaScript和TypeScript的实现方法。
|
1月前
|
存储 Linux API
深入探索Android系统架构:从内核到应用层的全面解析
本文旨在为读者提供一份详尽的Android系统架构分析,从底层的Linux内核到顶层的应用程序框架。我们将探讨Android系统的模块化设计、各层之间的交互机制以及它们如何共同协作以支持丰富多样的应用生态。通过本篇文章,开发者和爱好者可以更深入理解Android平台的工作原理,从而优化开发流程和提升应用性能。

推荐镜像

更多