Android源码中的单例模式
2016-01-27 10:57
369 查看
LayoutInflater 源码浅析
在Android中,我么常用LayoutInflater来加载一个布局,通常我们使用LayoutInflater.from(Context)来获取LayoutInflater服务。在Android系统中我们经常会通过Context获取系统级别的服务,如WindowManagerService、ActivityManagerService等,LayoutInflater也是其中之一,这些服务会在合适的时候以单例的形式注册在系统中,在我们需要的时候通过Context的getSystemService(String name)获取。我们以LayoutInflater为例说明,接下来我们看看LayoutInflater.from(Context)的实现:[code]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的getSystemService(String name)方法,我们知道Context是一个抽象类,我们要看具体的实现还要找出Context的实现类。那么这个Context对象的具体实现类是什么呢?
其实在Application、Activity、Service都会存在一个Context对象,即Context的总个数为Activity个数 + Service个数 + 1.而我们使用LayoutInflater一般在Activity中使用,所以这个Context一定是Activity的Context。接下来我们从Activity的Context入手进行分析。
我们知道,一个Activity的入口是ActivityThread的main函数,在main函数中创建一个新的ActivityThread对象,并且启动消息循环(UI线程),创建新的Activity、新的Context对象,然后将该Context对象传递给Activity。下面看看ActivityThread源代码:
[code] 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(); if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); } private void attach(boolean system) { sCurrentActivityThread = this; mSystemThread = system; // 不是系统应用的情况 if (!system) { ViewRootImpl.addFirstDrawHandler(new Runnable() { @Override public void run() { ensureJitEnabled(); } }); android.ddm.DdmHandleAppName.setAppName("<pre-initialized>", UserHandle.myUserId()); RuntimeInit.setApplicationObject(mAppThread.asBinder()); final IActivityManager mgr = ActivityManagerNative.getDefault(); try { mgr.attachApplication(mAppThread); } catch (RemoteException ex) { // Ignore } // Watch for getting close to heap limit. BinderInternal.addGcWatcher(new Runnable() { @Override public void run() { if (!mSomeActivitiesChanged) { return; } Runtime runtime = Runtime.getRuntime(); long dalvikMax = runtime.maxMemory(); long dalvikUsed = runtime.totalMemory() - runtime.freeMemory(); if (dalvikUsed > ((3*dalvikMax)/4)) { if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024) + " total=" + (runtime.totalMemory()/1024) + " used=" + (dalvikUsed/1024)); mSomeActivitiesChanged = false; try { mgr.releaseSomeActivities(mAppThread); } catch (RemoteException e) { } } } }); } else { // Don't set application object here -- if the system crashes, // we can't display an alert, we just want to die die die. android.ddm.DdmHandleAppName.setAppName("system_process", UserHandle.myUserId()); try { mInstrumentation = new Instrumentation(); ContextImpl context = ContextImpl.createAppContext( this, getSystemContext().mPackageInfo); mInitialApplication = context.mPackageInfo.makeApplication(true, null); mInitialApplication.onCreate(); } catch (Exception e) { throw new RuntimeException( "Unable to instantiate Application():" + e.toString(), e); } } // add dropbox logging to libcore DropBox.setReporter(new DropBoxReporter()); ViewRootImpl.addConfigCallback(new ComponentCallbacks2() { @Override public void onConfigurationChanged(Configuration newConfig) { synchronized (mResourcesManager) { // We need to apply this change to the resources // immediately, because upon returning the view // hierarchy will be informed about it. if (mResourcesManager.applyConfigurationToResourcesLocked(newConfig, null)) { // This actually changed the resources! Tell // everyone about it. if (mPendingConfiguration == null || mPendingConfiguration.isOtherSeqNewer(newConfig)) { mPendingConfiguration = newConfig; sendMessage(H.CONFIGURATION_CHANGED, newConfig); } } } } @Override public void onLowMemory() { } @Override public void onTrimMemory(int level) { } }); }
在main方法中,我们创建一个ActivityThread对象后,调用了其attach函数,并且参数为false。在attach函数中,参数为false的情况下(即非系统应用),会通过Binder机制与ActivityManagerService通信,并且最终调用handleLaunchActivity函数,我们看看该函数的实现:
[code]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 activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); // 代码省略 } catch (Exception e) { // 代码省略 } try { // 创建Application对象 Application app = r.packageInfo.makeApplication(false, mInstrumentation); // 省略代码 if (activity != null) { // 获取Context对象 Context appContext = createBaseContextForActivity(r, activity); CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager()); Configuration config = new Configuration(mCompatConfiguration); // 省略代码 // 将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, r.voiceInteractor); // 省略代码 // 调用Activity的onCreate方法 if (r.isPersistable()) { mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); } else { mInstrumentation.callActivityOnCreate(activity, r.state); } // 代码省略 } catch (SuperNotCalledException e) { throw e; } catch (Exception e) { // 代码省略 } return activity; } private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) { // 创建Context对象,可以看到实现类是ContextImpl ContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, r.token); appContext.setOuterContext(activity); Context baseContext = appContext; // 省略代码 return baseContext; }
同过上面代码分析可以知道,Context的实现类为ContextImpl。我们继续跟踪ContextImpl类:
[code]class ContextImpl extends Context { // 代码省略 static class More ...ServiceFetcher { int mContextCacheIndex = -1; public Object getService(ContextImpl ctx) { ArrayList<Object> cache = ctx.mServiceCache; Object service; synchronized (cache) { if (cache.size() == 0) { // Initialize the cache vector on first access. // At this point sNextPerContextServiceCacheIndex // is the number of potential services that are // cached per-Context. for (int i = 0; i < sNextPerContextServiceCacheIndex; i++) { cache.add(null); } } else { service = cache.get(mContextCacheIndex); 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) { ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name); return fetcher == null ? null : fetcher.getService(this); } // 代码省略 }
从ContextImpl类的部分代码可以看到,在虚拟机第一次加载该类时会注册各种ServiceFetcher,其中就包含了LayoutInflater Service。将这些服务以键值对的形式存储在一个HashMap中,用户使用时只需要根据key来获取到对应的ServiceFetcher,然后通过ServiceFetcher对象的getService函数来获取具体的服务对象。当第一次获取时,会调用ServiceFetcher的createService函数创建服务对象,然后将该对象存到一个列表中,下次再取时从缓存中获取,避免重复创建对象,从而达到单例的效果。关于LayoutInflater的原理可以参考《 LayoutInflater源码深度分析笔记》这种方式我们在《确保对象的唯一性——单例模式》一文中有所介绍,大家有兴趣可以看一下。
相关文章推荐
- 推荐提升 Android 性能的建议
- Android开发者需要面对的8大挑战
- android:碎片的概念
- Android对应用程序签名
- Android命令Monkey压力测试,详解
- Android 图片裁剪功能实现详解(类似QQ自定义头像裁剪)
- android 图片相关
- android 动画
- 使用Gradle管理你的Android Studio工程
- 动态调试Android笔记
- Android基础知识学习记录
- Android:Unable to find explicit activity class
- AndroidKiller使用的命令
- Android的死机、重启问题分析方法
- 生成android证书
- 阅读《Android 从入门到精通》(18)——拖动条
- Android基础知识(2)
- android studio之如何删除项目中的依赖项目或者module
- Android-Plugin-Framework集成开发
- android技巧:神奇的android:clipChildren属性