Activity的显示过程

本文详细解析了Android中Activity从启动到显示的过程,包括Activity的attach方法内部实现、PhoneWindow的作用及初始化过程,以及如何通过WindowManager将DecorView添加到屏幕进行显示。

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

上一篇文章提到在ActivityThread会调用performLaunchActivity() 这个函数里面会调用Activity的attach()方法。这个attach就是初始化一些Activity的东西具体代码如下:

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) {
        attachBaseContext(context);

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

        //得到当前Activity的phoneWindow
        mWindow = new PhoneWindow(this, window);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
            mWindow.setSoftInputMode(info.softInputMode);
        }
        if (info.uiOptions != 0) {
            mWindow.setUiOptions(info.uiOptions);
        }
        mUiThread = Thread.currentThread();

        mMainThread = aThread;
        mInstrumentation = instr;
        mToken = token;
        mIdent = ident;
        mApplication = application;
        mIntent = intent;
        mReferrer = referrer;
        mComponent = intent.getComponent();
        mActivityInfo = info;
        mTitle = title;
        mParent = parent;
        mEmbeddedID = id;
        mLastNonConfigurationInstances = lastNonConfigurationInstances;
        if (voiceInteractor != null) {
            if (lastNonConfigurationInstances != null) {
                mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
            } else {
                mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
                        Looper.myLooper());
            }
        }

        //把当前Activity的phoneWindow和WindowManager联系起来
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        if (mParent != null) {
            mWindow.setContainer(mParent.getWindow());
        }
        mWindowManager = mWindow.getWindowManager();
        mCurrentConfig = config;
    }

代码不多就全部贴出来,说到显示过程我们在attach里面主要关注下面三句
//得到当前Activity的phoneWindow
mWindow = new PhoneWindow(this, window);
//把当前Activity的phoneWindow和WindowManager联系起来
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
mWindowManager = mWindow.getWindowManager();
这三句就是把phoneWindow(activity的窗口里面包含mDecorView)和windowManager绑定起来,attach就先分析到这里;
我们会在onCreate()调用setContentView(),里面会把对应的view添加到mDecorView里面,执行完onCreate()之后ActivityManagerService会回调onResume(),在回调的过程中

final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
        ...
            if (r.window == null && !a.mFinished && willBeVisible) {
                r.window = r.activity.getWindow();
                View decor = r.window.getDecorView();
                decor.setVisibility(View.INVISIBLE);
                //得到attach里面的 windowManager
                ViewManager wm = a.getWindowManager();
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                ...
                if (a.mVisibleFromClient && !a.mWindowAdded) {
                    a.mWindowAdded = true;
                    //把decorView添加进来
                    wm.addView(decor, l);
                }

            // If the window has already been added, but during resume
            // we started another activity, then don't yet make the
            // window visible.
            } else if (!willBeVisible) {
                if (localLOGV) Slog.v(
                    TAG, "Launch " + r + " mStartedActivity set");
                r.hideForNow = true;
            }

            ...
                if (r.activity.mVisibleFromClient) {
                //把mDecorView显示出来
                    r.activity.makeVisible();
                }
            }

            ...

        } else {
            // If an exception was thrown when trying to resume, then
            // just end this activity.
            try {
                ActivityManagerNative.getDefault()
                    .finishActivity(token, Activity.RESULT_CANCELED, null,
                            Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }
    }

可以看到activity的显示过程实际就是调用windowManager.addView();

Window是一个抽象的概念,每一个Window都对应着一个View和一个ViewRootImpl,Window和View通过ViewRootImpl来建立联系,就像(activity的)phoneWindow和popUpWindow 我们设置setContentView来绑定对应的view;
说明View才是Window存在的实体,在实际使用中无法直接访问Window,对Window的访问必须通过WindowManager,比如window的添加过程我们会通过WindowManager.addView(),但是windowManager是一个接口,它具体的实现类是WindowManagerImpl类,但是WindowManagerImpl没有具体实现ViewManager的addView()、updateLayoutView()、removeView(),而是交给WindowManagerGlobal去实现。添加view具体实现步骤如下:
1、检查参数是否合法,如果是子Window那么嗨需要调整一些布局参数
2、创建ViewRootImpl并将View添加到列表
3、通过ViewRootImpl来更新界面并完成Window的添加过程

### 启动并显示另一个 Activity 的方式 在 Android 应用开发中,要在一个 `Activity` 中启动并显示另一个 `Activity`,通常通过调用 `startActivity()` 方法实现。当应用程序进程已处于运行状态时,会调用 `ActivityStackSupervisor.startSpecificActivity` 方法来处理新活动的创建与展示请求,最终由 `realStartActivityLocked` 完成实际操作[^1]。 具体来说,在源代码层面涉及多个函数调用来完成这一过程,包括但不限于 `resumeFocusedStackTopActivityLocked`, `startSpecificActivityLocked -> realStartActivityLocked` 等方法共同协作以确保新的 `Activity` 能够被正确加载到前台可见位置[^2]。 下面是一个简单的例子展示了如何从当前 `Activity` A 启动一个新的 `Activity` B: ```java // 假设这是位于ActivityA中的按钮点击事件处理器 Intent intent = new Intent(this, ActivityB.class); startActivity(intent); // 使用此语句可以启动指定的目标activity ``` 上述代码片段中,`this` 表示当前上下文即 `ActivityA` 实例;而 `ActivityB.class` 则指定了想要跳转至的新组件类名。一旦执行了这段逻辑,则系统将会按照既定机制去准备并呈现目标界面给用户查看。 #### 创建用于传递数据的意图对象 有时可能还需要向即将打开的新页面传入一些参数信息以便于后者初始化自身UI或其他资源。此时可以通过设置额外的数据字段附加到意图对象上来达成目的: ```java Intent intent = new Intent(this, ActivityB.class); intent.putExtra("key", value); // 添加键值对形式的数据项作为附加工具携带过去 startActivity(intent); ``` 这里的关键在于利用 `putExtra(String name, Bundle bundle)` 或者其他重载版本的方法为待发送的消息包增加必要的属性描述,从而允许接收方能够获取这些预先设定好的配置选项来进行个性化定制工作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值