android源码设计模式解析与实战 读书笔记 2 单例模式(下)

来源:互联网 发布:小明看看地址永久域名 编辑:程序博客网 时间:2024/05/17 09:44

android源码中的单例模式:LayoutInflater。
LayoutInflater的获取通过context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);Context是一个抽象类,我们需要找到它的具体实现。一个Activity的入口时ActivityThread的main方法,在main方法中,会调用其attach函数,参数为false(非系统应用),在attach中会通过Binder机制与ActivityManagerService通信,并且最终调用handleLaunchActivity函数,在该函数会调用performLaunchActivity函数,之后就会通过createBaseContextForActivity函数为该Activity创建Context,从中我们可以知道Context的具体实现类是ContextImpl。在ContextImpl中维护了一个SYSTEM_SERVICE_MAP的Service静态容器,并在其的静态语句块中实现了对LAYOUT_INFLATER_SERVICE服务的注册,至此我们就发现LAYOUT_INFLATER_SERVICE就是通过之前的静态实现的单例的。

深入理解LayoutInflater:
LayoutInflater是一个抽象类,所以我们还需要找到它的具体实现,从刚刚将LAYOUT_INFLATER_SERVICE注册入手。如下代码

registerService(LAYOUT_INFLATER_SERVICE,new ServiceFetcher(){
public Object createService(ContextImpl ctx){
return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
}
})

继续看PolicyManager.makeNewLayoutInflater方法:

public LayoutInflater makeNewLayoutInflater(Context context){    return sPolicy.makeNewLayoutInflater(context);}// 在Policy中public LayoutInflater makeNewLayoutInflater(Context context){    return new PhoneLayoutInflater(context);}

至此我们知道LayoutInflater的具体实现类是PhoneLayoutInflater,继续深入看PhoneLayoutInfla

public class PhoneLayoutInflater extends LayoutInflater{/* 内置View类型的前缀,如TextView的完整路径是android.widget.TextView*/private static final String[] sClassPrefixList={"android.widget","android.webkit"};protect View onCreateView(String name,AttributeSet attires)throws ClassNotFoundException{for(String prefix :sClassPrefixList){View view = createView(name,prefix,attires);if(view  != null){return view;}}return super.onCreateView(name,attrs);}}

通过传递进来的View的名字加上前缀得到完整路径来构造对应的View对象。

具体流程:
Activity的setContentView会调用Window的同名方法,而Window的具体实现时PhoneWindow,如下是PhoneWindow中对应方法:

public void setContentView(int layoutResID){    //当mContentParent为空时先构建DecorView,并将包裹到mContentParent中    if(mContentParent == null){        installDecor();    }else{        mContentParent.removeAllViews();    }    //解析layoutResID    mLayoutInflater.inflate(layoutResID,mContentParent);}

在看下一个Window的View层级结构,从外到内分别是:Activity-PhoneWindow-DecorView-DefaultLayout-ViewGroup mContentParent-用户自己的XML布局。

接下来就是解析XML,并将其中的View添加到mContentParent中来。
inflater方法的主要有下面几步:

  1. 解析XML中根标签(第一个元素);
  2. 如果根标签是merge,那么调用rInflate进行解析,rInflate会merge标签下的所有子View直接添加到根标签中;
  3. 如果标签是普通元素,那么调用createViewFromTag对该元素进行解析;
  4. 调用rInflate解析temp根元素下的所有子View,并且将这些子View都添加到temp下;
  5. 返回解析到的根视图。

主要分析下createViewFromTag:

  1. 首先判断用户是否设置LayoutInflater的factory来自行解析View(忽略);
  2. 通过View的name中是否包含”.”来区分是自定义控件还是系统控件,系统控件将会拼接成完整的路径,这样就保证后面创建View时使用的是完整路径;
  3. 通过反射构造View(这里有构造函数的缓存处理)。

看完构造View,在看解析整个视图树,由rInflate完成;rInflate通过深度优先遍历来构造视图树,每解析到一个View元素就会递归rInflate,直到这条路径下的最后一个元素,然后再回溯过来将每个View元素添加到它们的parent中。通过rInflate的解析之后,整个视图树就构建完成,从而显示在我们的视野中。

运用单例模式:

在我们使用的ImageLoader中,它的创建我们就是使用的DCL单例,代码如下:

public static ImageLoader getInstance(){
if(sInstance == null){
synchronized(ImageLoader.class){
if(sInstance == null){
sInstance = new ImageLoader();
}
}
}
}

单例优点:

  1. 由于单例模式在内存中只有一个实例,减少类内存开支;
  2. 减少类系统的性能开销;
  3. 可以避免对资源的多重占用;
  4. 可以在系统设置全局的访问点,优化和共享资源访问;

单例缺点:
1. 一般没有接口,扩展很困难;
2. 单例如果持有Context,很容易引发内存泄漏,此时应使用ApplicationContext来代替。

0 0
原创粉丝点击