2019-09-17 16:08:59 liufulin520328 阅读数 26
  • Android设计模式精解(第7课) :Adapter模式

    接口设计是缔造系统整合架构之美的基础。例如,在上一章里,说明过Android框架里常呈现 Template Method与Abstract Factory模式联合运用的结构,其中有两个重要的接口,搭配得似乎完美了。不过,本章的Adapter模式将进一步隐藏AbstractProduct类别(及Use接口),并提供一个新的接口给Client类别使用,更满足Client的期待,追求更高的美感。

    6503 人正在学习 去看看 高煥堂

前言:

Android 的设计模式系列文章,欢迎star,持续更新。。。

Android 的设计模式---单例模式

Android 的设计模式---建造者模式

Android 的设计模式---三种工厂模式

Android 的设计模式---策略模式

Android 的设计模式---责任链模式

Android 的设计模式---观察者模式

单例介绍:某个类只有一个实例,并且自行实例化并向整个系统提供这个唯一实例。

多种单例创建模式介绍:

(一) 饿汉式:

public class Singleton {

    //饿汉式
    private Singleton() {   //使用private 是为了防止外部new 多个singleton对象
    }

    private final static Singleton singletion = new Singleton(); //直接生成一个类的对象

    public static Singleton getSingletion() {
        return singletion;
    }

    //优点:写法简单,线程安全
    //缺点:没有懒加载的效果,在没有使用到该类的时候会造成内存浪费

}

(二) 懒汉式:

public class Singleton {
    //懒汉式
    private Singleton() {   //使用private 是为了防止外部new 多个singleton对象
    }

    private static Singleton singletion = null;  //声明一个null 对象

    /**
     * 优点:实现了懒加载
     * 缺点:线程不安全
     * @return
     */
    public static Singleton getSingletion1() {  //   在第一个获取的时候才实例化
        if (singletion == null) {
            singletion = new Singleton();
        }
        return singletion;
    }

    /**
     * 加一个 synchronized 关键字,达到同步效果
     * 优点: 实现了懒加载,线程安全
     * 缺点:使用synchronized会造成不必要的同步开销,而且大部分时候我们是用不到同步的。
     * @return
     */
    public static synchronized Singleton getInstance2() {
        if (singletion == null) {
            singletion = new Singleton();
        }
        return singletion;
    }
    
}

(三)双重检查锁定:

public class Singleton {
    //双重检查锁定
    private Singleton() {   //使用private 是为了防止外部new 多个singleton对象
    }

    //volatile 能够防止代码的重排序,保证得到的对象是初始化过
    private volatile  static Singleton singleton;

    /**
     * 双重锁检测
     * 优点:懒加载,线程安全,执行效率高
     * 缺点:volatile影响一点性能,高并发下有一定的缺陷,某些情况下DCL会失效,虽然概率较小
     * @return
     */
    public static Singleton getInstance(){
        if (singleton==null){
            synchronized (Singleton.class){
                if (singleton==null){
                    singleton=new Singleton();
                }
            }
        }
        return  singleton;
    }

}

(推荐使用) 静态内部类:

public class Singleton {
    // 静态内部类
    private Singleton() {   //使用private 是为了防止外部new 多个singleton对象
    }

    /**
     * 第一次调用的时候才加载SingletonViewHolder并初始化singleton
     *
     * @return
     */
    public static Singleton getInstance() {
        return SingletonViewHolder.singleton;
    }

    /**
     * 静态内部类
     */
    private static class SingletonViewHolder {
        private final static Singleton singleton = new Singleton();
    }
}

单例使用场景(优点):

  1. 本质是控制实例的数量
  2. 频繁访问数据库或文件的对象
  3. 工具类对象
  4. 创建对象时耗时过多或耗费资源过多,但又经常用到的对象

 (缺点)

  1. 获取对象时不能用new
  2. 单例对象如果持有Context,那么很容易引发内存泄露
  3. 单例模式一般没有接口,扩展很困难,若要扩展,只能修改代码来实现
2017-11-28 17:03:14 Conan9715 阅读数 853
  • Android设计模式精解(第7课) :Adapter模式

    接口设计是缔造系统整合架构之美的基础。例如,在上一章里,说明过Android框架里常呈现 Template Method与Abstract Factory模式联合运用的结构,其中有两个重要的接口,搭配得似乎完美了。不过,本章的Adapter模式将进一步隐藏AbstractProduct类别(及Use接口),并提供一个新的接口给Client类别使用,更满足Client的期待,追求更高的美感。

    6503 人正在学习 去看看 高煥堂

Android系统源码中的单例模式:
代码路径:/frameworks/base/core/java/android/util/Singleton.java

package android.util;
/**
 * Singleton helper class for lazily initialization.
 *
 * Modeled after frameworks/base/include/utils/Singleton.h
 *
 * @hide
 */
public abstract class Singleton<T> {
    private T mInstance;

    protected abstract T create();

    public final T get() {
        synchronized (this) {
            if (mInstance == null) {
                mInstance = create();
            }
            return mInstance;
        }
    }
}

调用位置之一是Activity工作流程中ActivityManagerNative.getDefault().startActivity,这里的ActivityManagerNative.getDefault返回ActivityManagerService的远程接口,即ActivityManagerProxy接口,具体不做讨论,详见老罗(罗升阳)的博客:
Android系统在新进程中启动自定义服务过程(startService)的原理分析
Android应用程序启动过程源代码分析
ActivityManagerNative.getDefault()源码调用如下:

/**
     * Retrieve the system's default/global activity manager.
     */
    static public IActivityManager getDefault() {
        return gDefault.get();
    }
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
        protected IActivityManager create() {
            IBinder b = ServiceManager.getService("activity");
            if (false) {
                Log.v("ActivityManager", "default service binder = " + b);
            }
            IActivityManager am = asInterface(b);
            if (false) {
                Log.v("ActivityManager", "default service = " + am);
            }
            return am;
        }
    };

该单例模式实现方式中的Java设计模式有: 单例模式, 模板方法模式mInstance = create();
再加一个使用示例如下:

public class SingletonTest {

    private static final Singleton<SingletonTest> gDefault = new Singleton<SingletonTest>(){

        @Override
        protected SingletonTest create() {
            return new SingletonTest();
        }
    };

    private SingletonTest(){}

    public static SingletonTest getInstance(){
        return gDefault.get();
    }
}

该单例模式的实现方式其实是采用了静态内部类.

public class Singleton {
    private static class Holder {
        private static Singleton singleton = new Singleton();
    }

    private Singleton(){}

    public static Singleton getSingleton(){
        return Holder.singleton;
    }
}

这种方式利用了类加载机制。既做到了延时加载,并且能保证线程安全,我们可以把Singleton实例放到一个静态内部类中,这样就避免了静态实例在Singleton类加载的时候就创建对象,并且由于静态内部类只会被加载一次,所以这种写法也是线程安全的。

本文参考自:
Java单例模式——并非看起来那么简单
你真的会写单例模式吗——Java实现
你真的会写单例模式吗——Java实现

不当之处,欢迎指正
android交流群:230274309

2015-10-15 08:52:14 sbsujjbcy 阅读数 6531
  • Android设计模式精解(第7课) :Adapter模式

    接口设计是缔造系统整合架构之美的基础。例如,在上一章里,说明过Android框架里常呈现 Template Method与Abstract Factory模式联合运用的结构,其中有两个重要的接口,搭配得似乎完美了。不过,本章的Adapter模式将进一步隐藏AbstractProduct类别(及Use接口),并提供一个新的接口给Client类别使用,更满足Client的期待,追求更高的美感。

    6503 人正在学习 去看看 高煥堂

对于开发人员来说,设计模式有时候就是一道坎,但是设计模式又非常有用,过了这道坎,它可以让你水平提高一个档次。而在android开发中,必要的了解一些设计模式又是非常有必要的。对于想系统的学习设计模式的同学,这里推荐2本书。一本是Head First系列的Head Hirst Design Pattern,英文好的可以看英文,可以多读几遍。另外一本是大话设计模式。

这篇文章介绍一个模式,就是单例模式,因为个人觉得这个模式理解起来最容易,而且不是太复杂。

首先了解一些什么是单例,从名字中就可以听出来就是在内存中维护唯一对象。这样做有以下几个优点

  • 对于那些比较耗内存的类,只实例化一次可以大大提高性能,尤其是在移动开发中。
  • 保持程序运行的时候该中始终只有一个实例存在内存中

其实单例有很多种实现方式,但是个人比较倾向于其中1种。可以见单例模式

代码如下

public class Singleton {
    private static volatile Singleton instance = null;

    private Singleton(){
    }

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

要保证单例,需要做一下几步

  • 必须防止外部可以调用构造函数进行实例化,因此构造函数必须私有化。
  • 必须定义一个静态函数获得该单例
  • 单例使用volatile修饰
  • 使用synchronized 进行同步处理,并且双重判断是否为null,我们看到synchronized (Singleton.class)里面又进行了是否为null的判断,这是因为一个线程进入了该代码,如果另一个线程在等待,这时候前一个线程创建了一个实例出来完毕后,另一个线程获得锁进入该同步代码,实例已经存在,没必要再次创建,因此这个判断是否是null还是必须的。

至于单例的并发测试,可以使用CountDownLatch,使用await()等待锁释放,使用countDown()释放锁从而达到并发的效果。可以见下面的代码

public static void main(String[] args) {
    final CountDownLatch latch = new CountDownLatch(1);
    int threadCount = 1000;
    for (int i = 0; i < threadCount; i++) {
        new Thread() {
            @Override
            public void run() {
                try {
                    latch.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Singleton.getInstance().hashCode());
            }
        }.start();
    }
    latch.countDown();
}

看看打印出来的hashCode会不会出现不一样即可,理论上是全部都一样的。

而在Android中,很多地方用到了单例。

比如Android-Universal-Image-Loader中的单例

private volatile static ImageLoader instance;
/** Returns singleton class instance */
public static ImageLoader getInstance() {
    if (instance == null) {
        synchronized (ImageLoader.class) {
            if (instance == null) {
                instance = new ImageLoader();
            }
        }
    }
    return instance;
}

比如EventBus中的单例

private static volatile EventBus defaultInstance;
public static EventBus getDefault() {
    if (defaultInstance == null) {
        synchronized (EventBus.class) {
            if (defaultInstance == null) {
                defaultInstance = new EventBus();
            }
        }
    }
    return defaultInstance;
}

上面的单例都是比较规规矩矩的,当然实际上有很多单例都是变了一个样子,单本质还是单例。

如InputMethodManager 中的单例

static InputMethodManager sInstance;
public static InputMethodManager getInstance() {
    synchronized (InputMethodManager.class) {
        if (sInstance == null) {
            IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
            IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);
            sInstance = new InputMethodManager(service, Looper.getMainLooper());
        }
        return sInstance;
    }
}

AccessibilityManager 中的单例,看代码这么长,其实就是进行了一些判断,还是一个单例

private static AccessibilityManager sInstance;
public static AccessibilityManager getInstance(Context context) {
    synchronized (sInstanceSync) {
        if (sInstance == null) {
            final int userId;
            if (Binder.getCallingUid() == Process.SYSTEM_UID
                    || context.checkCallingOrSelfPermission(
                            Manifest.permission.INTERACT_ACROSS_USERS)
                                    == PackageManager.PERMISSION_GRANTED
                    || context.checkCallingOrSelfPermission(
                            Manifest.permission.INTERACT_ACROSS_USERS_FULL)
                                    == PackageManager.PERMISSION_GRANTED) {
                userId = UserHandle.USER_CURRENT;
            } else {
                userId = UserHandle.myUserId();
            }
            IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
            IAccessibilityManager service = IAccessibilityManager.Stub.asInterface(iBinder);
            sInstance = new AccessibilityManager(context, service, userId);
        }
    }
    return sInstance;
}

当然单例还有很多种写法,比如恶汉式,有兴趣的自己去了解就好了。

最后,我们应用一下单例模式。典型的一个应用就是管理我们的Activity,下面这个可以作为一个工具类,代码也很简单,也不做什么解释了。

public class ActivityManager {

    private static volatile ActivityManager instance;
    private Stack<Activity> mActivityStack = new Stack<Activity>();

    private ActivityManager(){

    }

    public static ActivityManager getInstance(){
        if (instance == null) {
        synchronized (ActivityManager.class) {
            if (instance == null) {
                instance = new ActivityManager();
            }
        }
        return instance;
    }

    public void addActicity(Activity act){
        mActivityStack.push(act);
    }

    public void removeActivity(Activity act){
        mActivityStack.remove(act);
    }

    public void killMyProcess(){
        int nCount = mActivityStack.size();
        for (int i = nCount - 1; i >= 0; i--) {
            Activity activity = mActivityStack.get(i);
            activity.finish();
        }

        mActivityStack.clear();
        android.os.Process.killProcess(android.os.Process.myPid());
    }
}

这个类可以在开源中国的几个客户端中找到类似的源码

以上两个类是一样的,没区别。

2019-07-10 11:14:13 kidults 阅读数 361
  • Android设计模式精解(第7课) :Adapter模式

    接口设计是缔造系统整合架构之美的基础。例如,在上一章里,说明过Android框架里常呈现 Template Method与Abstract Factory模式联合运用的结构,其中有两个重要的接口,搭配得似乎完美了。不过,本章的Adapter模式将进一步隐藏AbstractProduct类别(及Use接口),并提供一个新的接口给Client类别使用,更满足Client的期待,追求更高的美感。

    6503 人正在学习 去看看 高煥堂
2018-04-17 17:37:09 suncold123 阅读数 264
  • Android设计模式精解(第7课) :Adapter模式

    接口设计是缔造系统整合架构之美的基础。例如,在上一章里,说明过Android框架里常呈现 Template Method与Abstract Factory模式联合运用的结构,其中有两个重要的接口,搭配得似乎完美了。不过,本章的Adapter模式将进一步隐藏AbstractProduct类别(及Use接口),并提供一个新的接口给Client类别使用,更满足Client的期待,追求更高的美感。

    6503 人正在学习 去看看 高煥堂

更多的关于设计模式与源码的内容都在我的github
我的博客

单例模式

核心原理: 将构造函数私有化,并且通过静态方法获取一个唯一的实例,在这个过程中必须保证线程安全、防止反序列化导致重新生成实例对象等问题。

  • UML
    单例设计模式

单例模式实现的几种方式

饿汉式

/**
 * 饿汉式
 */
public class Singleton {

    private static Singleton instance = new Singleton();

    private Singleton(){}

    public static Singleton getInstance() {
        return instance;
    }
}

懒汉式

/**
 * 懒汉式
 */
public class Singleton {

    private static Singleton instance;

    private Singleton(){}

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

Double Check Lock(DCL)实现单例模式

/**
 * Double Check Lock(DCL) 双重锁校验
 * 优点:资源利用率高,但是由于Java内存模型的问题偶尔会出现DCL失效问题
 */
public class Singleton {

    private static Singleton instance = null;

    private Singleton() {
    }

    public static Singleton getInstance() {
        //避免不必要的同步
        if (instance == null) {
            synchronized (Singleton.class) {
                //在null的情况下创建实例
                if (instance == null) {
                    /**
                     * 1.给Singleton的实例分配内存
                     * 2.调用Singleton()的构造函数
                     * 3.将instance对象指向分配的空间
                     *
                     * 因为JVM编译器对象允许处理器乱序执行,所以这三步顺序不一定
                     */
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

静态内部类单例模式

/**
 * 静态内部类单例模式(推荐使用)
 * 能够保证线程安全,对象的唯一性,延迟了单例的实例化。
 */
public class Singleton {

    private Singleton(){}

    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }

    /**
     * 静态内部类
     */
    private static class SingletonHolder{
        private static final Singleton instance = new Singleton();
    }

}

枚举单例

/**
 * 枚举单例
 *  写法简单,默认枚举实例的创建是线程安全的。
 *  在上述的几种单例模式的实现中,在反序列化的情况下会出现重新创建对象的情况。
 */
public enum SingletonEnum {
    INSTANCE;
    public void doSomething(){
        System.out.println("do sth");
    }
}

/**
 * 防止单例对象被反序列化,重写反序列化的一个钩子函数readResolve()
 */
public final class Singleton implements Serializable{

    public static final Singleton INSTANCE = new Singleton();

    public static Singleton getInstance() {
        return INSTANCE;
    }

    /**
     * 反序列化操作中可以让那个开发人员控制对象的函数
     * @return
     * @throws ObjectStreamException
     */
    private Object readResolve() throws ObjectStreamException{
        return INSTANCE;
    }

}

容器实现单例模式

/**
 * 使用容器实现单例模式
 */
public class SingletonManager {
    private static Map<String,Object> objMap = new HashMap<String,Object>();

    private SingletonManager(){}

    public static void registerService(String key,Object instance){
        if (!objMap.containsKey(key)){
            objMap.put(key,instance);
        }
    }

    public static Object getInstance(String key){
        return objMap.get(key);
    }

}

单例模式在Android源码中的应用(LayoutInflater)

  1. 通过LayoutInflater.from(context)来获取LayoutInflater服务
/**
 * Obtains the LayoutInflater from the given 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;
}
  1. 来看看context.getSystemService是怎么工作的,context的实现类是ContextImpl类,点进去看一下
@Override
public Object getSystemService(String name) {
    return SystemServiceRegistry.getSystemService(this, name);
}
  1. 进入到SystemServiceRegistry类中
/**
 * Gets a system service from a given context.
 */
public static Object getSystemService(ContextImpl ctx, String name) {
    ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
    return fetcher != null ? fetcher.getService(ctx) : null;
}

看到这里感觉好像是我们上面用到的第五种单例模式,使用容器实现。看一下果然是

private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
        new HashMap<String, ServiceFetcher<?>>();

使用map通过键值对的方式保存系统服务。在调用registerService的时候注入。

/**
 * Statically registers a system service with the context.
 * This method must be called during static initialization only.
 */
private static <T> void registerService(String serviceName, Class<T> serviceClass,
        ServiceFetcher<T> serviceFetcher) {
    SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
    SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
}
  1. 我们可以再看看这些系统服务都是在什么时候注册的
static {

registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
        new CachedServiceFetcher<LayoutInflater>() {
    @Override
    public LayoutInflater createService(ContextImpl ctx) {
        return new PhoneLayoutInflater(ctx.getOuterContext());
    }});
}

是在一个静态的代码块中进行注册服务,第一次加载该类的时候执行,并且只执行一次,保证实例的唯一性。

从这个过程中可以看出,系统将服务以键值对的形式存储在HashMap中,用户使用时只需要获取具体的服务对象,第一次获取时,调用getSystemService来获取具体的对象,在第一次调用时,会调用registerService通过map将对象缓存在一个列表中,下次再用时直接从容器中取出来就可以。避免重复创建对象,从而达到单例的效果。减少了资源消耗。

  1. 接下来,我们继续深入研究一下LayoutInflater的源码实现,我们知道LayoutInflater是一个抽象类,具体的实现肯定都在它的子类,在注册服务的时候可以之后它的子类就是PhoneLayoutInflater.
/**
 * @hide
 */
public class PhoneLayoutInflater extends LayoutInflater {
   //内置View类型的前缀,拼接出完整路径 andorid.widget.TextView
    private static final String[] sClassPrefixList = {
        "android.widget.",
        "android.webkit.",
        "android.app."
    };

    /**
     * Instead of instantiating directly, you should retrieve an instance
     * through {@link Context#getSystemService}
     *
     * @param context The Context in which in which to find resources and other
     *                application-specific things.
     *
     * @see Context#getSystemService
     */
    public PhoneLayoutInflater(Context context) {
        super(context);
    }

    protected PhoneLayoutInflater(LayoutInflater original, Context newContext) {
        super(original, newContext);
    }

    /** Override onCreateView to instantiate names that correspond to the
        widgets known to the Widget factory. If we don't find a match,
        call through to our super class.
    */
    @Override protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException {
        for (String prefix : sClassPrefixList) {
            try {
                View view = createView(name, prefix, attrs);
                if (view != null) {
                    return view;
                }
            } catch (ClassNotFoundException e) {
                // In this case we want to let the base class take a crack
                // at it.
            }
        }
     //核心语句,根据我完整View的的路径名来构造出View对象
        return super.onCreateView(name, attrs);
    }

    public LayoutInflater cloneInContext(Context newContext) {
        return new PhoneLayoutInflater(this, newContext);
    }
}

从上述代码中我们可以看出 为什么当我们自定义View的时候需要把全类名写上。

  1. 看一下一个View的构建流程,以ActivitysetContentView为
/**
 * Set the activity content from a layout resource.  The resource will be
 * inflated, adding all top-level views to the activity.
 *
 * @param layoutResID Resource ID to be inflated.
 *
 * @see #setContentView(android.view.View)
 * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
 */
public void setContentView(@LayoutRes int layoutResID) {
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}

实际上是调用WindowsetContentView,window是一个抽象类,子类是PhoneWindow,具体来看下

@Override
public void setContentView(int layoutResID) {
    // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
    // decor, when theme attributes and the like are crystalized. Do not check the feature
    // before this happens.
//如果为空,安装DecorView,并将DecorView添加到mContentParent中
    if (mContentParent == null) {
        installDecor();
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        mContentParent.removeAllViews();
    }

    if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                getContext());
        transitionTo(newScene);
    } else {
    //通过布局id和mContentParent渲染布局,解析xml文件
        mLayoutInflater.inflate(layoutResID, mContentParent);
    }
    mContentParent.requestApplyInsets();
    final Callback cb = getCallback();
    if (cb != null && !isDestroyed()) {
        cb.onContentChanged();
    }
    mContentParentExplicitlySet = true;
}

看一下infate方法,主要就是解析xml文件的标签

public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
    synchronized (mConstructorArgs) {
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");

        final Context inflaterContext = mContext;
        final AttributeSet attrs = Xml.asAttributeSet(parser);
        Context lastContext = (Context) mConstructorArgs[0];
        mConstructorArgs[0] = inflaterContext;
        View result = root;

        try {
            // Look for the root node.
            int type;
            while ((type = parser.next()) != XmlPullParser.START_TAG &&
                    type != XmlPullParser.END_DOCUMENT) {
                // Empty
            }

            if (type != XmlPullParser.START_TAG) {
                throw new InflateException(parser.getPositionDescription()
                        + ": No start tag found!");
            }

            final String name = parser.getName();

            if (DEBUG) {
                System.out.println("**************************");
                System.out.println("Creating root view: "
                        + name);
                System.out.println("**************************");
            }

            if (TAG_MERGE.equals(name)) {
                if (root == null || !attachToRoot) {
                    throw new InflateException("<merge /> can be used only with a valid "
                            + "ViewGroup root and attachToRoot=true");
                }

                rInflate(parser, root, inflaterContext, attrs, false);
            } else {
                // Temp is the root view that was found in the xml
                final View temp = createViewFromTag(root, name, inflaterContext, attrs);

                ViewGroup.LayoutParams params = null;

                if (root != null) {
                    if (DEBUG) {
                        System.out.println("Creating params from root: " +
                                root);
                    }
                    // Create layout params that match root, if supplied
                    params = root.generateLayoutParams(attrs);
                    if (!attachToRoot) {
                        // Set the layout params for temp if we are not
                        // attaching. (If we are, we use addView, below)
                        temp.setLayoutParams(params);
                    }
                }

                if (DEBUG) {
                    System.out.println("-----> start inflating children");
                }

                // Inflate all children under temp against its context.
                rInflateChildren(parser, temp, attrs, true);

                if (DEBUG) {
                    System.out.println("-----> done inflating children");
                }

                // We are supposed to attach all the views we found (int temp)
                // to root. Do that now.
                if (root != null && attachToRoot) {
                    root.addView(temp, params);
                }

                // Decide whether to return the root that was passed in or the
                // top view found in xml.
                if (root == null || !attachToRoot) {
                    result = temp;
                }
            }

        ....//省略代码

        return result;
    }
}

rInflate通过深度优先遍历来构造视图树,每解析一个View元素就会递归调用rInflte,会将每个View元素添加到parent中,最后最后,通过setContentView设置的内容就会出现在屏幕上。

void rInflate(XmlPullParser parser, View parent, Context context,
        AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException {

    final int depth = parser.getDepth();
    int type;

    while (((type = parser.next()) != XmlPullParser.END_TAG ||
            parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {

        if (type != XmlPullParser.START_TAG) {
            continue;
        }

        final String name = parser.getName();

        if (TAG_REQUEST_FOCUS.equals(name)) {
            parseRequestFocus(parser, parent);
        } else if (TAG_TAG.equals(name)) {
            parseViewTag(parser, parent, attrs);
        } else if (TAG_INCLUDE.equals(name)) {
            if (parser.getDepth() == 0) {
                throw new InflateException("<include /> cannot be the root element");
            }
            parseInclude(parser, context, parent, attrs);
        } else if (TAG_MERGE.equals(name)) {
            throw new InflateException("<merge /> must be the root element");
        } else {
            final View view = createViewFromTag(parent, name, context, attrs);
            final ViewGroup viewGroup = (ViewGroup) parent;
            final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
            rInflateChildren(parser, view, attrs, true);
            viewGroup.addView(view, params);
        }
    }

    if (finishInflate) {
        parent.onFinishInflate();
    }
}

小结:单例模式是运用最多的设计模式之一,在客户端没有高并发的情况下,选择那种实现方式并没有太大的影响,但出于效率考虑,推荐使用DCL和静态内部类的实现方式。

java、Android单例模式

博文 来自: u010936731
没有更多推荐了,返回首页