Android源码中的单例模式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lijizhi19950123/article/details/79510430

前言

在Android系统中,我们经常会通过Context获取系统级别的服务,如WindowsManager,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(layoutInflter == null) {
   throw new AssertionError("LayoutInflater not fount.");
}
return layoutInflater ;   
}

可以看到from(Context) 函数内部调用的是Context类的getSystemService(String key)方法,我们跟踪到Context类看到,该类是一个抽象类:

public abstract class Context {
  //省略代码
}

getView中使用的Context对象的具体实现类是什么呢?

其实在Application,Activity,Service中都会存在一个Context对象,即Contextde的总个数为Activity个数+Service个数+1.而ListView通常都是显示在Activity中,那么我们就以Activity中的Context来分析。
我们知道,一个Activity的入口是ActivityThread的main函数,在main函数中创建一个新的ActivityThread对象,并且启动消息循环(UI线程),创建新的Activity,新的Context对象,然后将该Context对象传递给Activity。下面看看Activity。下面看看ActivityThread的源代码:

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

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

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

private void attach(boolean system) {
   sThreadLocal.set(this);
   mSystemThread = system;
   // 不是系统应用的情况
   if(!system){
       ViewRootImpl.addFirstDrawHandler(new Runnable(){
       public void run(){
       ensureJitEnabled();
       }
       });
  android.ddm.DdmHandlerAppName.setAppName("<pre-initialized>",UserHandler.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机制与ActivityManagerService通信,并且最终调用handleLaunchActivity函数,我们看看该函数的实现:

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent){
//代码省略
Activity a = perfromLaunchActivity(r, customIntent);
//代码省略private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent){
//代码省略
Activity activity = null;
try{
   java.lang.ClassLoader c1 = r.packageInfo.getClassLoader();
   //1.创建Activity
   activity=mInstrumentation.newActivity(
       c1,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,getInstrustmenttation,r.token,r.ident,app,r,intent,r,activityInfo,title,r.parent,......)

//代码省略
//4.调用Activity的onCreate方法
mInstrumentation.callActivityOnCreate(activity,r.state);
//代码省略
 } catch(SuperNotCallException e)
 throw 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的实现类为 ContextImpl。 我们继续跟踪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;
 }
}

/**
*子类覆写该方法用以创建服务对象
*/

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 insranceof StaticServiceCache)) {
fetcher.mContextCacheIndex = sNextPerContextServiceCachgeIndex++;
}
//3. 静态语句块,第一次加载该类时执行(只执行一次保证实例的唯一性)
static {
// 代码省略
//注册LayoutInflater service
registerService(LAYOUT_INFLATER_SERVICE,new ServiceFetcher(){
  public Object createService(ContextImpl ctx) {
  return PolicyManager.makeNewLayout(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函数创建服务对象。然后将对象缓存到一个列表里,下次再取时直接从缓存中获取,避免重复创建对象,从而达到单例的效果。

猜你喜欢

转载自blog.csdn.net/lijizhi19950123/article/details/79510430