Activity UI显示流程分析

本文深入探讨了Android Activity的UI显示流程,从Activity启动、视图设置到显示的整个过程。分析了setContentView()方法如何加载布局资源,以及DecorView和PhoneWindow的角色。通过时序图和类关系图,解释了为何设置window属性需在setContentView()之前,以及为何Activity在onResume()后才对用户可见。
摘要由CSDN通过智能技术生成

在鄙视链底端的客户端开发经常被调侃为“调UI的”、“切图boy”。调侃归调侃,我们该调的UI还得调,但是呢,我们不能止步于此。对于我们调的UI是怎么在Activity上显示,这个我们是不是该了解下呢?

 在我们开发一个有交互的Android App时,我们第一步就是定义一个Activity,然后在Activity的onCreate()方法中调用setContentView()并传入布局文件,这就开始了我们调UI的第一步了。使用很简单,不过作为专业调UI的,我们是不是该想一想:布局文件是怎么显示在Activity上的呢?另外当我们设置window的flag或者feature的时候为什么要在setContentView()之前呢?为什么说Activity UI是在onResume()方法后对用户才是可见的呢?

Activity启动

  在我们开始分析Activity是如何显示前,我们先来了解Activity是如何启动的。对于Activity启动阶段中的ActivityTask判断和管理,我们这里不展开,我们直接看Activity的最后启动的阶段。Activity启动的最后阶段是在ActivityThread.performLaunchActivity()完成的。

/**  Core implementation of activity launch. */
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
   
    //省略部分代码.......
    //创建context
    ContextImpl appContext = createBaseContextForActivity(r);
    Activity activity = null;
    try {
   
        java.lang.ClassLoader cl = appContext.getClassLoader();
        //创建activity对象
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
        StrictMode.incrementExpectedActivityCount(activity.getClass());
        r.intent.setExtrasClassLoader(cl);
        r.intent.prepareToEnterProcess();
        if (r.state != null) {
   
            r.state.setClassLoader(cl);
        }
    } catch (Exception e) {
   
        if (!mInstrumentation.onException(activity, e)) {
   
            throw new RuntimeException(
                "Unable to instantiate activity " + component
                + ": " + e.toString(), e);
        }
    }

    try {
   
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);

        if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
        if (localLOGV) Slog.v(
                TAG, r + ": app=" + app
                + ", appName=" + app.getPackageName()
                + ", pkg=" + r.packageInfo.getPackageName()
                + ", comp=" + r.intent.getComponent().toShortString()
                + ", dir=" + r.packageInfo.getAppDir());

        if (activity != null) {
   
            CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
            Configuration config = new Configuration(mCompatConfiguration);
            if (r.overrideConfig != null) {
   
                config.updateFrom(r.overrideConfig);
            }
            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                    + r.activityInfo.name + " with config " + config);
            Window window = null;
            if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
   
                window = r.mPendingRemoveWindow;
                r.mPendingRemoveWindow = null;
                r.mPendingRemoveWindowManager = null;
            }
            appContext.setOuterContext(activity);
            //调用activity.attach方法,并传入Context、Application、window等对象
            activity.attach(appContext, this, getInstrumentation(), r.token,
                    r.ident, app, r.intent, r.activityInfo, title, r.parent,
                    r.embeddedID, r.lastNonConfigurationInstances, config,
                    r.referrer, r.voiceInteractor, window, r.configCallback);

            if (customIntent != null) {
   
                activity.mIntent = customIntent;
            }
            r.lastNonConfigurationInstances = null;
            checkAndBlockForNetworkAccess();
            activity.mStartedActivity = false;
            int theme = r.activityInfo.getThemeResource();
            if (theme != 0) {
   
                activity.setTheme(theme);
            }

            activity.mCalled = false;
            if (r.isPersistable()) {
   
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
   
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
            //如果Activity在onCreate方法中调用父类的onCreate则抛出异常。
            if (!activity.mCalled) {
   
                throw new SuperNotCalledException(
                    "Activity " + r.intent.getComponent().toShortString() +
                    " did not call through to super.onCreate()");
            }
            r.activity = activity;
        }
        r.setState(ON_CREATE);

        mActivities.put(r.token, r);

    } catch (SuperNotCalledException e) {
   
        throw e;

    } catch (Exception e) {
   
        if (!mInstrumentation.onException(activity, e)) {
   
            throw new RuntimeException(
                "Unable to start activity " + component
                + ": " + e.toString(), e);
        }
    }

    return activity;
}

 在该方法中主要是做了以下几件事:

  • 创建Activity的Context
  • 创建Application对象
  • 调用Activity.attach()方法并传入Context、Application、Window等对象。

 我们只关注重要的方法Activity.attach();

final void attach(Context context, ActivityThread aThread,
        Instrumentation instr, IBinder token, int ident,
        Application application, Intent intent, ActivityInfo info,
        CharSequence title, Activity parent, String id,
        NonConfigurationInstances lastNonConfigurationInstances,
        Configuration config, String referrer, IVoiceInteractor voiceInteractor,
        Window window, ActivityConfigCallback activityConfigCallback) {
   
    attachBaseContext(context);

    mFragments.attachHost(null /*parent*/);

    mWindow = new PhoneWindow(this, window, activityConfigCallback);
    mWindow.setWindowControllerCallback(this);
    mWindow.setCallback(this);
    mWindow.setOnWindowDismissedCallback(this);
    mWindow.getLayoutInflater().setPrivateFactory
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值