解析 setContentView(R.layout.activity_home)流程

本文详细剖析了Android应用中Activity如何通过setContentView()加载布局的过程,从AppCompatActivity到AppCompatDelegate,再到AppCompatDelegateImpl,解释了布局XML文件如何通过LayoutInflater解析并添加到视图树中,帮助开发者深入了解Android应用的内部工作机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们使用activity,设置布局的时候会用setContentView(R.layout.activity_home),那到底是怎么加载的呢?

public class HomeActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);

    }
}

1 首先进入AppCompatActivity---->setcontentview,看下源码

public class AppCompatActivity extends FragmentActivity implements AppCompatCallback,TaskStackBuilder.SupportParentable, ActionBarDrawerToggle.DelegateProvider 


{ 
    //首先调用的是父类(AppCompatActivity)的setcontentView方法
    @Override
    public void setContentView(@LayoutRes int layoutResID) {
        getDelegate().setContentView(layoutResID);//接着调用的AppCompatDelegate的方法
    }

    //AppCompatDelegate 此类表示一个委托,您可以用来将AppCompat的支持扩展到任何activity 中
    @NonNull
    public AppCompatDelegate getDelegate() {
        if (mDelegate == null) {
            mDelegate = AppCompatDelegate.create(this, this);
        }
        return mDelegate;
    }
}

2 AppCompatDelegate 是一个抽象类,AppCompatDelegateImpl 是抽象类的实例。activity的步骤都在此类中代理操作。

public abstract class AppCompatDelegate {


   @NonNull
    public static AppCompatDelegate create(@NonNull Activity activity,
            @Nullable AppCompatCallback callback) {
        return new AppCompatDelegateImpl(activity, callback);//真实 的实例去操作
    }

}

3 AppCompatDelegateImpl 的具体步骤

@RestrictTo(LIBRARY)
class AppCompatDelegateImpl extends AppCompatDelegate
        implements MenuBuilder.Callback, LayoutInflater.Factory2 {


 1//构造方法,传入当前activity 和 当前activity window.callback
  AppCompatDelegateImpl(Activity activity, AppCompatCallback callback) {
        this(activity, null, callback, activity);
    }

2 //
 private AppCompatDelegateImpl(Context context, Window window, AppCompatCallback callback,
            Object host) {
        mContext = context;
        mAppCompatCallback = callback;
        mHost = host; //当前activity

        if (mLocalNightMode == MODE_NIGHT_UNSPECIFIED && mHost instanceof Dialog) {
            final AppCompatActivity activity = tryUnwrapContext();
            if (activity != null) {
                // This code path is used to detect when this Delegate is a child Delegate from
                // an Activity, primarily for Dialogs. Dialogs use the Activity as it's Context,
                // so we want to make sure that the this 'child' delegate does not interfere
                // with the Activity config. The simplest way to do that is to match the
                // outer Activity's local night mode
                mLocalNightMode = activity.getDelegate().getLocalNightMode();
            }
        }
        if (mLocalNightMode == MODE_NIGHT_UNSPECIFIED) {
            // Try and read the current night mode from our static store
            final Integer value = sLocalNightModes.get(mHost.getClass());
            if (value != null) {
                mLocalNightMode = value;
                // Finally remove the value
                sLocalNightModes.remove(mHost.getClass());
            }
        }

        if (window != null) {
            attachToWindow(window);
        }

        // Preload appcompat-specific handling of drawables that should be handled in a special
        // way (for tinting etc). After the following line completes, calls from AppCompatResources
        // to ResourceManagerInternal (in appcompat-resources) will handle those internal drawable
        // paths correctly without having to go through AppCompatDrawableManager APIs.
        AppCompatDrawableManager.preload();
    }

3//读取样式,设置window 背景等
private void attachToWindow(@NonNull Window window) {
        if (mWindow != null) {
            throw new IllegalStateException(
                    "AppCompat has already installed itself into the Window");
        }

        final Window.Callback callback = window.getCallback();
        if (callback instanceof AppCompatWindowCallback) {
            throw new IllegalStateException(
                    "AppCompat has already installed itself into the Window");
        }
        mAppCompatWindowCallback = new AppCompatWindowCallback(callback);
        // Now install the new callback
        window.setCallback(mAppCompatWindowCallback);

        final TintTypedArray a = TintTypedArray.obtainStyledAttributes(
                mContext, null, sWindowBackgroundStyleable);
        final Drawable winBg = a.getDrawableIfKnown(0);
        if (winBg != null) {
            // Now set the background drawable
            window.setBackgroundDrawable(winBg);
        }
        a.recycle();

        mWindow = window;
    }

4 //调用setContentView
 @Override
    public void setContentView(int resId) {
        ensureSubDecor(); //确保 phonewindow decordeview 绘制完成
        ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content); //content 是我们自己绘制view 的父布局
        contentParent.removeAllViews(); //先清理view
        LayoutInflater.from(mContext).inflate(resId, contentParent);//通过LayoutInflater 解析xml 文件生成view,然后contentParent.addview(读取resId 创建的view);
        mAppCompatWindowCallback.getWrapped().onContentChanged();
    }

4.1//确保创建 主题样式的根布局
 private void ensureSubDecor() {
        if (!mSubDecorInstalled) {
            mSubDecor = createSubDecor();

            // If a title was set before we installed the decor, propagate it now
            CharSequence title = getTitle();
            if (!TextUtils.isEmpty(title)) {
                if (mDecorContentParent != null) {
                    mDecorContentParent.setWindowTitle(title);
                } else if (peekSupportActionBar() != null) {
                    peekSupportActionBar().setWindowTitle(title);
                } else if (mTitleView != null) {
                    mTitleView.setText(title);
                }
            }

            applyFixedSizeWindow();

            onSubDecorInstalled(mSubDecor);

            mSubDecorInstalled = true;

            // Invalidate if the panel menu hasn't been created before this.
            // Panel menu invalidation is deferred avoiding application onCreateOptionsMenu
            // being called in the middle of onCreate or similar.
            // A pending invalidation will typically be resolved before the posted message
            // would run normally in order to satisfy instance state restoration.
            PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
            if (!mIsDestroyed && (st == null || st.menu == null)) {
                invalidatePanelMenu(FEATURE_SUPPORT_ACTION_BAR);
            }
        }


    }

总结:调用流程:我们创建的activity.setcontentview() --> AppCompatActivity.setcontentview() -->AppCompatDelegateImpl.setcontentview()

如何把xml 文件添加到根视图呢?通过 LayoutInflater.inflate(),在通过XmlResourceParser 解析xml 文件,生成xmlview,然后 contentv view.add(xmlview),一个view 树就创建完了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值