美文网首页
源码:setContentView(),Activity与App

源码:setContentView(),Activity与App

作者: xqiiitan | 来源:发表于2024-06-30 17:14 被阅读0次

Activity.setContentView() 界面是怎么实例化的。

目前能做到,获取另外一个没安装的apk的资源文件(网上下载的)

实现换肤功能:

  1. 每一次打开的都是新的皮肤;
  2. 换肤之后,所有的Activity里面的View都要换肤;
  3. 每次进入app也需要换肤。

解决方案:

  1. 每次进入activity,都要把需要换肤的View找出来,然后调用代码去换肤。比较死板的一种方法。
  2. 拿到根布局RootView,然后遍历里面的子View,通过tag
    android:tag="skin:background:blue_color@@textColor:black_color"
    解析tag,然后获取内容。设置背景和文字颜色。
  3. 拦截View的创建,目前是比较好的方案。创建的时候,所有的View 添加到集合中。
    点击换肤,遍历集合中所有的View, 去改变背景,color等。
    系统是如何加载界面的?

Activity.setContentView()

Activity.setContentView()-- getWindow().setContentView(layoutResID)
PhoneWindow.setContentView(layoutResID)-- installDecor()
-- mDecor = generateDecor()
-- mContentParent = generateLayout(mDecor) // 找到叫android.R.id.content 的FrameLayout。
-- mLayoutInflater.inflate(layoutResID, mContentParent)

DecorView 继承自FrameLayout。
系统布局里面有个FrameLayout,它的id 是 com.android.internal.R.id.content
public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;
mContentParent 就是内容的布局。

// PhoneWindow.java
protected ViewGroup generateLayout(DecorView decor) {
    // Inflate the window decor。加载源码里面系统的布局文件。
    // 找到合适的系统布局资源(eg:screen_simple,screen_simple_overlay_action_mode )
    int layoutResource; 
    View in = mLayoutInflater.inflate(layoutResource, null);
    decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); // 加载系统的布局到decor中。
    mContentRoot = (ViewGroup)in;
    ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
    return contentParent;
}
// layoutResID 就是 activity_main.xml, 也就是将自己的layout 加载到mContentParent中。
mLayoutInflater.inflate(layoutResID, mContentParent);

AppCompatActivity.setContentView() 区别?

主要是为了兼容低版本。

setContentView(layoutResID)
-- getDelegate().setContentView(layoutResID)
---- mDelegate = AppCompatDelegate.create(this, this);
------ create(activity, activity.getWindow(), callback) // 里面针对23,14,11 做不同的兼容。
------ return AppCompatDelegateImplV7(context, window, callback)
-- AppCompatDelegateImplV7.setContentView()

// AppCompatDelegateImplV7
@Override
public void setContentView(int resId) {
    ensureSubDecor(); // 
    ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);
    contentParent.removeAllViews();
    LayoutInflater.from(mContext).inflate(resId, contentParent);
    mAppCompatWindowCallback.getWrapped().onContentChanged();
}

// AppCompatDelegateImplV7
AppCompatDelegateImplV7 implements LayoutInflaterFactory (里面只有onCreateView(parent,name,context,attrs)接口)

// AppCompatDelegateImpl
@Override
public void installViewFactory() {
    LayoutInflater layoutInflater = LayoutInflater.from(mContext);
    if (layoutInflater.getFactory() == null) {
        LayoutInflaterCompat.setFactory2(layoutInflater, this);
    } else {
        if (!(layoutInflater.getFactory2() instanceof AppCompatDelegateImpl)) {
            Log.i(TAG, "The Activity's LayoutInflater already has a Factory installed"
                    + " so we can not install AppCompat's");
        }
    }
}
// LayoutInflaterCompat
public static void setFactory2(
        @NonNull LayoutInflater inflater, @NonNull LayoutInflater.Factory2 factory) {
    inflater.setFactory2(factory);

    if (Build.VERSION.SDK_INT < 21) {
        final LayoutInflater.Factory f = inflater.getFactory();
        if (f instanceof LayoutInflater.Factory2) {
            // The merged factory is now set to getFactory(), but not getFactory2() (pre-v21).
            // We will now try and force set the merged factory to mFactory2
            forceSetFactory2(inflater, (LayoutInflater.Factory2) f);
        } else {
            // Else, we will force set the original wrapped Factory2
            forceSetFactory2(inflater, factory);
        }
    }
}
// AppCompatDelegateImpl.createView
// --mAppCompatViewInflater.createView()
// AppCompatViewInflater.createView()  switch-case,完成View的替换
// 只要继承自AppCompatActivity,创建的View都会走入AppCompatViewInflater.createView()
// 这个方法.  在这个方法中完成View的替换。

总结:区别:

ImageView mImageView;
继承自 Activity: 图片对象是 android.widget.ImageView 对象。
继承自 AppCompatActivity: 图片对象是 android.support.v7.widget.AppCompatImageView 对象。
这样做到低版本的兼容。比如tint属性可在低版本中使用。

原因:创建View的时候,AppCompatActivity 会拦截,不会走系统的LayoutInflater的创建。
从而View就会被替换掉。从而达到兼容低版本,让低版本也能使用Material Design等特性。

相关文章

网友评论

      本文标题:源码:setContentView(),Activity与App

      本文链接:https://www.haomeiwen.com/subject/pgdpcjtx.html