LayoutInflater与AppCompat理解

151 阅读3分钟

未命名文件 (1).png

  • LayoutInflater系统服务,抽象不能被外部实例化
  • 解析xml布局-XmlPullParser
  • 根据XmlPullParser创建View对象
  • rInflater添加到布局树
获取LayoutInflater实例
//获取LayoutInflater方法
LayoutInflater LayoutInflater =
        (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//真实使用
LayoutInflater.from(mContext).inflate(resId, contentParent);

context获取服务原理:理论上一个app只有一个服务实例

//获取服务方式 context.getSystemService 。eg:ActivityManager
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
//-->ContextWrapper.getSystemService
@Overridepublic Object getSystemService(String name) { return mBase.getSystemService(name);}
//-->mBase是Context的实现类ContextImpl
@Override
public Object getSystemService(String name) {
    return SystemServiceRegistry.getSystemService(this, name);
}
//-->SystemServiceRegistry.getSystemService
public static Object getSystemService(ContextImpl ctx, String name) {
    ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
    return fetcher != null ? fetcher.getService(ctx) : null;
}
//SystemServiceRegistry内部存储了静态代码快注册了所有需要存储的服务
private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
        new HashMap<String, ServiceFetcher<?>>();
        
//SystemServiceRegistry 静态代码快注册服务点        
static {
     //代码省略
registerService(Context.ACCESSIBILITY_SERVICE, AccessibilityManager.class,
        new CachedServiceFetcher<AccessibilityManager>() {
    @Override
    public AccessibilityManager createService(ContextImpl ctx) {
        return AccessibilityManager.getInstance(ctx);
    }});

registerService(Context.CAPTIONING_SERVICE, CaptioningManager.class,
        new CachedServiceFetcher<CaptioningManager>() {
    @Override
    public CaptioningManager createService(ContextImpl ctx) {
        return new CaptioningManager(ctx);
    }});
registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
        new CachedServiceFetcher<LayoutInflater>() {
    @Override
    public LayoutInflater createService(ContextImpl ctx) {
        return new PhoneLayoutInflater(ctx.getOuterContext());
    }});
     //代码省略
}

LayoutInflater在Activity中的创建过程

  • 每个 Context 都有其独立的 LayoutInflater(cloneInContext)
  • 根据SystemServiceRegistry注册LayoutInflater 实例为PhoneLayoutInflater
//ContextThemeWrapper 中重写了 getSystemService 方法
@Override
public Object getSystemService(String name) {
    if (LAYOUT_INFLATER_SERVICE.equals(name)) {
        if (mInflater == null) {
            // 每个Activity都有自己独一无二的Layoutflater
            // 这里首先拿到在SystemServiceRegistry中注册的Application的Layoutflater
            // 克隆LayoutInflater
            mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
        }
        return mInflater;
    }
    //其他服务的处理
    return getBaseContext().getSystemService(name);
}
PhoneLayoutInflater 源码
public class PhoneLayoutInflater extends LayoutInflater {
    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.
     * 
     * SystemServiceRegistry 的静态代码款中注册的。全局唯一
     * @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.
            }
        }

        return super.onCreateView(name, attrs);
    }
    //clone一个单独的实例
    public LayoutInflater cloneInContext(Context newContext) {
        return new PhoneLayoutInflater(this, newContext);
    }
}
Appcompat包对于LayoutInflater的适配
  • 委托类 AppCompatDelegate -->AppCompatDelegateImpl
    • 主要用于继承AppCompat支持任何的android.app.Activity
    • 支持生命周期管控
    • 支持黑白皮肤
    • 支持actionbar
    • 代理LayoutInflater布局解析
AppCompatDelegate LayoutInflater布局解析过程
  • setContentView-->ensureSubDecor
  • 创建subDecor
    • AppCompatDelegate - setContentView尝试创建subDecor
    • subDecor不是DecorView,
//创建mSubDecor
private void ensureSubDecor() {
   if (!mSubDecorInstalled) {
   //此处创建SubDecor
       mSubDecor = createSubDecor();
  //省略
}
//创建mSubDecor方法
private ViewGroup createSubDecor() {
  //省略
  //获取到PhoneWindow--初始化时创建了DecorView
   ensureWindow();
   //decorView==null会创建
   mWindow.getDecorView();

   final LayoutInflater inflater = LayoutInflater.from(mContext);
   ViewGroup subDecor = null;
   //创建subDecor省略 inflater.inflater创建的
   //将subDecor添加到布局上
   mWindow.setContentView(subDecor);
   //省略
   return subDecor;
}
  • 解析xml布局
   //解析xml
   public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
   final Resources res = getContext().getResources();
   //解析xml得到 XmlResourceParser
   XmlResourceParser parser = res.getLayout(resource);
   try {
   //创建View ,添加View布局树
       return inflate(parser, root, attachToRoot);
   } finally {
       parser.close();
   }
}
  • 创建View
//根据parser创建布局
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
   synchronized (mConstructorArgs) {
       //省略
      //查找xml布局的根节点
       advanceToRootNode(parser);
      // 找到起始根节点
      if (type != XmlPullParser.START_TAG) {
         throw new InflateException(parser.getPositionDescription()
                       + ": No start tag found!");
       }
           // 获取到节点名称
       final String name = parser.getName();
       //判断是否是merge
       if (TAG_MERGE.equals(name)) {
           if (root == null || !attachToRoot) {
               // 此时如果ViewGroup==null,与attachToRoot==false将会抛出异常
               // merge必须添加到ViewGroup中,这也是merge为什么要作为布局的根节点,它要添加到上层容器中
               throw new InflateException("<merge /> can be used only with a valid "
                       + "ViewGroup root and attachToRoot=true");
             }
         //将布局添加到布局树
         rInflate(parser, root, inflaterContext, attrs, false);
       } else {
           // 根据parser参数创建布局实例--重点
           final View temp = createViewFromTag(root, name, inflaterContext, attrs);
          //递归调用深度优先 解析child
           rInflateChildren(parser, temp, attrs, true);
           //添加布局
           if (root != null && attachToRoot) {
               root.addView(temp, params);
           }
            if (root == null || !attachToRoot) {
                   // 此时布局根节点为temp
                   result = temp;
           }
       }
       //省略若干
   }
}

  • 根据解析的xml创建对应的AppCompatView类型的布局,
//步骤
// createViewFromTag -> mFactory.onCreateView ->mAppCompatViewInflater.createView
final View createView(View parent, final String name, @NonNull Context context,
        @NonNull AttributeSet attrs, boolean inheritContext,
        boolean readAndroidTheme, boolean readAppTheme, boolean wrapContext)
    View view = null;
        case "TextView":
            view = createTextView(context, attrs);
            verifyNotNull(view, name);
            break;
        case "ImageView":
            view = createImageView(context, attrs);
            verifyNotNull(view, name);
            break;
        case "Button":
            view = createButton(context, attrs);
            verifyNotNull(view, name);
            break;
        case "EditText":
            view = createEditText(context, attrs);
            verifyNotNull(view, name);
            break;
        //省略
        default:
            view = createView(context, name, attrs);
    }
}