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

    xiaoxiao2024-07-06  109

    本节书摘来自异步社区《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函数创建服务对象,然后将该对象缓存到一个列表中,下次再取时直接从缓存中获取,避免重复创建对象,从而达到单例的效果。这种模式就是小节中通过容器的单例模式实现方式,系统核心服务以单例形式存在,减少了资源消耗。

    相关资源:Android源码设计模式解析与实战(高清版)
    最新回复(0)