android 源码中的单例模式

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

@Override
public View getView(int position,View convertView,ViewGroup parent){
<span style="white-space:pre">	</span>View itemView = null;
<span style="white-space:pre">	</span>if(convertView == null){
<span style="white-space:pre">		</span>itemView = LayoutInflate,from(mContext).inflate(mLayoutId,null);
<span style="white-space:pre">		</span>//代码省略
<span style="white-space:pre">	</span>}else{
<span style="white-space:pre">		</span>//代码省略
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>return itemView;

}
通常我们使用LayoutInflate.from(context)来获取LayoutInflate服务,下面看看LayoutInflate.from(context)  的实现:

public static LayoutInflate from(Context context){
<span style="white-space:pre">	</span>LayoutInflater layoutinflater = (LayoutInflater)context.getSystemService(Context.Layout_Inflater_service);
<span style="white-space:pre">	</span>if(layoutinflater == null){
<span style="white-space:pre">		</span>throw new AsserionError("LayoutInflater not found.");
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>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的入口是main函数,在main 函数中创建一个新的ActivityThread对象,并且启动消息循环,创建新的Activity,新的Context对象,然后将Context对象传递给Activity。下面看看ActivityThread源代码。

</pre><pre name="code" class="java">public static void main(String[] args){
<span style="white-space:pre">	</span>Process.setArgVo("<pre-initialized>");
<span style="white-space:pre">	</span>//主线程消息循环
<span style="white-space:pre">	</span>Looper.prepareMainLooper();
<span style="white-space:pre">	</span>//创建ActivityThread对象<span style="white-space:pre">	</span>
<span style="white-space:pre">	</span>ActivityThread thread = new ActivityThread();<span style="white-space:pre">	</span>
<span style="white-space:pre">	</span>thread.attach(false);
<span style="white-space:pre">	</span>if(sMainTHreadHandler == null){
<span style="white-space:pre">		</span>sMainthreadHandler = thread.getHandler();
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>AsyncTask.init();
<span style="white-space:pre">	</span>///代码省略
<span style="white-space:pre">	</span>Looper.loop();
}
</pre><pre name="code" class="java">private void attach(boolean system){
<span style="white-space:pre">	</span>sTgreadLocal.get(this);
<span style="white-space:pre">	</span>mSystenTgread = system;
<span style="white-space:pre">	</span>//不是系统应用
<span style="white-space:pre">	</span>if(!system){
<span style="white-space:pre">		</span>ViewRootImpl.addFirestDrawHandler(new Runnable(){
<span style="white-space:pre">			</span>public void run(){
<span style="white-space:pre">				</span>ensureJitEnabled();
<span style="white-space:pre">			</span>}<span style="white-space:pre">	</span>
<span style="white-space:pre">		</span>});
<span style="white-space:pre">		</span>abdroid.ddm.DdmHandler.setAppName(<span style="font-family: Arial, Helvetica, sans-serif;">"<pre-initialized>",UserHandler.myUserId());</span>
<span style="white-space:pre">		</span>RuntimeInit.<span style="font-family: Arial, Helvetica, sans-serif;">getApplicationObject</span><span style="font-family: Arial, Helvetica, sans-serif;">(mAppTHread.asBinder());</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre">				</span>  IActivityManager mgr = ActivityManagerNative.getDefault();</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre">				</span>try{</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre">					</span>//关联mAppThread</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre">	</span><span style="white-space:pre">		</span></span><span style="font-family: Arial, Helvetica, sans-serif;">		</span>mgr.attachApplication(mAppThread);
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre">				</span>}catch(RemoteException e){</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre">				</span>}</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre">		</span>}else{</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre">		</span>}</span>
}<span style="white-space:pre">	</span>
在main方法中,我们创建一个个ActivityThread实例后,调用了attach函数,并且参数为false。在attach函数中,参数为false的情况下,会通过Binder机制与ActivityManagerService通信,并且最终屌用handlerLaunchActivity函数,我们看看该函数的实现:

private void handleLaunchActivity(ActivityClientRecord r,Intent customIntent){
<span style="white-space:pre">	</span>Activity a = performLaunchActivity(r,customIntent);
<span style="white-space:pre">	</span>//代码省略
}
private Activity performLaunchActivity(ActivityClientRecord r,Intent customIntent){
<pre name="code" class="java"><span style="white-space:pre">	</span>//代码省略
Activity activity = null;
 
<span style="white-space:pre">	</span>try{
<span style="white-space:pre">		</span>java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
<span style="white-space:pre">		</span>activity = mInstrumentation.newActivity(cl,component.getClassName(),r.intent);
<span style="white-space:pre">		</span><span style="font-family: Arial, Helvetica, sans-serif;">//代码省略</span>
<span style="white-space:pre">	</span>}catch(Exception e){
<pre name="code" class="java"><span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre">				</span>//代码省略</span>
 
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>try{
<span style="white-space:pre">		</span>//创建Application对象
<span style="white-space:pre">		</span>Application app = r.packageInfp.makeApplication(false,mInstrumentation);
<span style="white-space:pre">		</span>if(activity != null){
<span style="white-space:pre">			</span>Context appContext = createBaseContextForActivity(r,activity);
<span style="white-space:pre">			</span>CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
<span style="white-space:pre">			</span>Configuration config = new Contiguration(mCompatConfiguration);
<span style="white-space:pre">			</span>activity.attach(appContext,this,getInstrumentation(),r.token,r.ident,app,r.intent,r.activityInfo,title,r.parent,r.embeddedId,r.lastNonConfigurationInstances,config);
<span style="white-space:pre">			</span>mInstrumentation.callActivityOnCreate(activity,r.state);
<span style="white-space:pre">			</span><span style="font-family: Arial, Helvetica, sans-serif;">//代码省略</span>
<span style="white-space:pre">		</span>}
<span style="white-space:pre">	</span>}catch(SuperNotCalledException e){
<span style="white-space:pre">		</span>//代码省略
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>return activity;
}
</pre><pre name="code" class="java">private Context createBaseContextForActivity(ActivityClientRecord r,final Activity activity){
<span style="white-space:pre">	</span>ContextImpl appContext = ContextImpl.createActivityContext(this,r.packageInfo,r.token);
<span style="white-space:pre">	</span>appContext.setOuterContext(activity);
<span style="white-space:pre">	</span>Context baseContext = appContext;
<span style="white-space:pre">	</span>return baseContext;
}
通过上面的代码分析可以知道,Context的实现类为ContextImpl。我们继续跟踪ContextImpl类:

class ContextImpl extends Context{
<span style="white-space:pre">	</span>//代码省略
<span style="white-space:pre">	</span>//ServerFetcher 通过getService 获取服务对象
<span style="white-space:pre">	</span>static class ServiceFetcher{
<span style="white-space:pre">		</span>int mContextCacheIndex = -1;
<span style="white-space:pre">		</span>//获取系统服务
<span style="white-space:pre">		</span>public Object getService(ContextImpl ctx){
<span style="white-space:pre">			</span>ArrayKust<Object> cacge = ctx.mServiceCache;
<span style="white-space:pre">			</span>Object service;
<span style="white-space:pre">			</span>synchronized(cache){
<span style="white-space:pre">				</span>if(cache.size() == 0){
<span style="white-space:pre">					</span>for(int i=0;i<sNextPerContextServuceCacheIndex;i++){
<span style="white-space:pre">						</span>cache.add(null);
<span style="white-space:pre">					</span>}<span style="white-space:pre">	</span>
<span style="white-space:pre">				</span>}else{
<span style="white-space:pre">					</span>service = cache.get(mContextCacheIndex);
<span style="white-space:pre">					</span>if(service != null){
<span style="white-space:pre">						</span>return sevice;
<span style="white-space:pre">					</span>}
<span style="white-space:pre">				</span>}
<span style="white-space:pre">				</span>service = createService(ctx);
<span style="white-space:pre">				</span>cache.set(mContextCacheIndex,service);
<span style="white-space:pre">				</span>return service;
<span style="font-family: Arial, Helvetica, sans-serif;">							</span><span style="font-family: Arial, Helvetica, sans-serif;">}</span><span style="font-family: Arial, Helvetica, sans-serif;">	</span>
<span style="white-space:pre">		</span>}
<span style="white-space:pre">		</span>//子类腹泻该方法以创建服务对象
<span style="white-space:pre">		</span>public Object createService(ContextImpl ctx){
<span style="white-space:pre">			</span>throw new RuntimeException("not implemented");
<span style="white-space:pre">		</span>}
<span style="white-space:pre">	</span>}
</pre><pre name="code" class="java"><span style="white-space:pre">	</span>private static final HashMap<String,ServiceFetcher> SYSTEM_SERVICE_MAP = new HashMap<String,ServiceFetcher>();
<span style="white-space:pre">	</span>private static int sNextPerZContextServiceCacheIndex = 0;
<span style="white-space:pre">	</span>private static void registerService(String seviceName,ServiceFetcher fetcher){
<span style="white-space:pre">		</span>if(!(fetcher instance of ServiceFetcher){
<span style="white-space:pre">			</span>fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
<span style="white-space:pre">		</span>}
<span style="white-space:pre">		</span>SYSTEM_SERVICE_MAP.put(serviceName,fetcher);
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>
<span style="white-space:pre">	</span>static{
<span style="white-space:pre">		</span>registerService(LAYOUT_INFLATER_SERVICE,new ServuceFetcher(){
<span style="white-space:pre">			</span>public Object createServie(ContextImpl ct){
<span style="white-space:pre">				</span>return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
<span style="white-space:pre">			</span>}
<span style="white-space:pre">		</span>});
<span style="white-space:pre">	</span>}
</pre><pre name="code" class="java"><span style="white-space:pre">	</span>@Override
<span style="white-space:pre">	</span>public Object getSystemService(String name){
<span style="white-space:pre">		</span>ServiceFetcher fetcher = SYSTEM_SERVUCE_MAP.get(name);
<span style="white-space:pre">		</span>return fetcher == null?null : fetcher.getService(this);
</pre><pre name="code" class="java"><span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>//代码省略
}
</pre><span style="white-space:pre">	</span>从ContextImpl类的部分代码中可以看到,在虚拟机第一次夹在该类时会注册各种ServiceFetcher,其中就包括了LayoutInflater Srevice。将这些服务以键值对的形式存储在一个HashMap中,用户使用时只需要根据Key来获取到对应的ServiceFetcher,然后通过ServiceFetcher的get Service函数来获取具体的服务对象。当第一次获取时,会调用createService函数创建服务对象,然后将该对象缓存到一个列表中,下次再取时直接从缓存中获取,避免重复创建对象,从而达到单例的效果。这种创建系统服务单例的模式减少了资源的消耗<p></p><p></p><pre name="code" class="java">


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值