当前位置: 首页 > article >正文

frameworks 之 Activity添加View

frameworks 之 Activity添加View

  • 1 LaunchActivityItem
    • 1.1 Activity 创建
    • 1.2 PhoneWindow 创建
    • 1.3 DecorView 创建
  • 2 ResumeActivityItem

讲解 Activity加载View的时机和流程
涉及到的类如下

  • frameworks/base/core/java/android/app/Activity.java
  • frameworks/base/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
  • frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java
  • frameworks/base/core/java/android/view/WindowManagerImpl.java

从之前文章Activity启动流程可知,最终会到 ActivityTaskSupervisor 的 realStartActivityLocked 方法,而 realStartActivityLocked 最终会执行 2个主要步骤 就是 LaunchActivityItemResumeActivityItem

1 LaunchActivityItem

1.1 Activity 创建

LaunchActivityItem 的 又会调用 ActivityThreadhandleLaunchActivity 方法

	public void execute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
        ActivityClientRecord r = client.getLaunchingActivity(token);
        client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
    }

handleLaunchActivity 又会调用 performLaunchActivity 方法

public Activity handleLaunchActivity(ActivityClientRecord r,
            PendingTransactionActions pendingActions, Intent customIntent) {
        ...
        final Activity a = performLaunchActivity(r, customIntent);
		...
        return a;
    }

performLaunchActivity 方法中

  1. 通过反射调用对应的 Activity
  2. 调用 Activity的 attach 方法创建phoneWindow
  3. 通过 callActivityOnCreate 执行 Activity的 onCreate方法
  4. 设置 ActivityClientRecord 状态为 ON_CREATE
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
        ContextImpl appContext = createBaseContextForActivity(r);
        // 进行反射创建对应的 Activity对象
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess(isProtectedComponent(r.activityInfo),
                    appContext.getAttributionSource());
            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 (activity != null) {
                ...
                // 调用 attach方法创建对应的的phoneView和 windowMangerImpl
                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,
                        r.assistToken, r.shareableActivityToken);
				...
				r.activity = activity;
                // 触发Activity的 onCreate方法
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                ...
            }
            // 设置 ActivityRecord状态为 ON_CREATE
            r.setState(ON_CREATE);

        } 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;
    }

1.2 PhoneWindow 创建

查看上面 Attach 方法

  1. 创建了 PhoneWindow
  2. 调用 phoneWindow的setWindowManager 方法 创建对应 WindowManagerImpl 对象。
  3. 将创建的WindowManagerImpl 赋值给 mWindowManager
final void attach(Context context, ActivityThread aThread...) {
		...
		// 初始化 PhoneWindow
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        ...
		// 初始化 并设置WindowManager到phoneWindow对应的变量
        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());
        }
        // 将上一步通过 setWindowManager 创建WindowManagerImpl并赋值给 mWindowManager
        mWindowManager = mWindow.getWindowManager();
}

1.3 DecorView 创建

执行了 Activity onCreate 方法后 ,我们就会对其调用 setContentView 将要显示的布局ID创建创建视图,setContentView 方法又会调用 phoneWindowsetContentView方法

	public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }

phoneWindowsetContentView主要做了

  1. 判断 mContentParent 是否为空(放应用要显示的布局容器),为空的话 则调用 installDecor 方法,创建 DecorView 和 内容容器 mContentParent
  2. 调用 inflate 将布局加载到 mContentParent 布局容器中
	public void setContentView(int layoutResID) {
        // 如果contentview为空则加载decorView
        if (mContentParent == null) {
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }

        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                    getContext());
            transitionTo(newScene);
        } else {
            // 将对应的布局加载到对应的内容区域
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
        ...
    }

其中 installDecor 方法主要逻辑

  1. 判断 mDecor 是否为空 ,为空的话调用 generateDecor 方法**(直接new DecorView),,并赋值**
  2. 判断 mContentParent 是否为空,为空的话 调用 generateLayout() 方法获取对应的容器.(里面会通过feature 加载对应的布局,然后获取R.id.content的控件),并返回。
  3. 根据属性 设置对应的标题。
	private void installDecor() {
        mForceDecorInstall = false;
        // 为空则创建 DecorView
        if (mDecor == null) {
            mDecor = generateDecor(-1);
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
            }
        } else {
            mDecor.setWindow(this);
        }
        // 为空则获取 decorView 用布局加载好里面的id为content的viewgroup
        if (mContentParent == null) {
            mContentParent = generateLayout(mDecor);
				...
                mTitleView = findViewById(R.id.title);
                if (mTitleView != null) {
                    if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
                        final View titleContainer = findViewById(R.id.title_container);
                        if (titleContainer != null) {
                            titleContainer.setVisibility(View.GONE);
                        } else {
                            mTitleView.setVisibility(View.GONE);
                        }
                        mContentParent.setForeground(null);
                    } else {
                        mTitleView.setText(mTitle);
                    }
                }
            }
        }
    }

generateLayout 主要

  1. 获取一系列属性
  2. 调用 getLocalFeatures 生成对应的 features,根据获取到的属性获取对应的布局ID赋值到 layoutResource
  3. 调用 decorView 的 onResourcesLoaded 方法 inflage出对应的布局,并通过 addView添加到 decorView,赋值给对应的mContentRoot 属性
  4. 根据mDecorView获取ID为 R.id.content的内容容器,并返回出去
protected ViewGroup generateLayout(DecorView decor) {
        ...
        // 获取设置一系列属性
        mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false);
        int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)
                & (~getForcedWindowFlags());
		...
        // Inflate the window decor.
        // 获取对应的 layout布局文件
        int layoutResource;
        int features = getLocalFeatures();
        // System.out.println("Features: 0x" + Integer.toHexString(features));
        if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
            if (mIsFloating) {
                TypedValue res = new TypedValue();
                getContext().getTheme().resolveAttribute(
                        R.attr.dialogTitleIconsDecorLayout, res, true);
                layoutResource = res.resourceId;
            } else {
                layoutResource = R.layout.screen_title_icons;
            }
            // XXX Remove this once action bar supports these features.
            removeFeature(FEATURE_ACTION_BAR);
            // System.out.println("Title Icons!");
        } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
                && (features & (1 << FEATURE_ACTION_BAR)) == 0) {
            // Special case for a window with only a progress bar (and title).
            // XXX Need to have a no-title version of embedded windows.
            layoutResource = R.layout.screen_progress;
            // System.out.println("Progress!");
        } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
            // Special case for a window with a custom title.
            // If the window is floating, we need a dialog layout
            if (mIsFloating) {
                TypedValue res = new TypedValue();
                getContext().getTheme().resolveAttribute(
                        R.attr.dialogCustomTitleDecorLayout, res, true);
                layoutResource = res.resourceId;
            } else {
                layoutResource = R.layout.screen_custom_title;
            }
            // XXX Remove this once action bar supports these features.
            removeFeature(FEATURE_ACTION_BAR);
        } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
            // If no other features and not embedded, only need a title.
            // If the window is floating, we need a dialog layout
            if (mIsFloating) {
                TypedValue res = new TypedValue();
                getContext().getTheme().resolveAttribute(
                        R.attr.dialogTitleDecorLayout, res, true);
                layoutResource = res.resourceId;
            } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
                layoutResource = a.getResourceId(
                        R.styleable.Window_windowActionBarFullscreenDecorLayout,
                        R.layout.screen_action_bar);
            } else {
                layoutResource = R.layout.screen_title;
            }
            // System.out.println("Title!");
        } else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
            layoutResource = R.layout.screen_simple_overlay_action_mode;
        } else {
            // Embedded, so no decoration is needed.
            layoutResource = R.layout.screen_simple;
            // System.out.println("Simple!");
        }

        
        mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
        // 根据mDecorView获取ID为 R.id.content
        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
        if (contentParent == null) {
            throw new RuntimeException("Window couldn't find content container view");
        }
		...
        return contentParent;
    }

2 ResumeActivityItem

经过 onCreate 视图view都创建准备好后,就会进入 resume阶段
ResumeActivityItem 又会执行对应的 handleResumeActivity 方法。

	public void execute(ClientTransactionHandler client, ActivityClientRecord r,
            PendingTransactionActions pendingActions) {
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
        // 执行 ActivityThread 的 handleResumeActivity
        client.handleResumeActivity(r, true /* finalStateRequest */, mIsForward,
                "RESUME_ACTIVITY");
        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
    }

handleResumeActivity 方法

  1. 从 ActivityClientRecord 取出 创建的 Activity,。将 decorView 设置为 INVISIBLE
  2. 将对应的 LayoutParams type 层级设置为 WindowManager.LayoutParams.TYPE_BASE_APPLICATION
  3. 调用 phoneWindow 创建的 WindowManagerImpl(attach创建) ,调用 addView 将 decorView添加到 WMS中
public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
            boolean isForward, String reason) {
		...
        final Activity a = r.activity;
		...
        final int forwardBit = isForward
                ? WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;

        // If the window hasn't yet been added to the window manager,
        // and this guy didn't finish itself or start another activity,
        // then go ahead and add the window.
        boolean willBeVisible = !a.mStartedActivity;
        if (!willBeVisible) {
            willBeVisible = ActivityClient.getInstance().willActivityBeVisible(
                    a.getActivityToken());
        }
        if (r.window == null && !a.mFinished && willBeVisible) {
            // 赋值 phoneWindow 给ActivityClientRecord
            r.window = r.activity.getWindow();
            View decor = r.window.getDecorView();
            decor.setVisibility(View.INVISIBLE);
            ViewManager wm = a.getWindowManager();
            WindowManager.LayoutParams l = r.window.getAttributes();
            // 将 decor赋值给activity
            a.mDecor = decor;
            // 设置Activity的层级为application
            l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
            l.softInputMode |= forwardBit;
           	...
            // 将decorView 通过 wms添加到容器中
            if (a.mVisibleFromClient) {
                if (!a.mWindowAdded) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);
                } 
            }
        }
    }

WindowManagerImpl 添加时候 又会调用 全局单例WindowManagerGlobal 添加

public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyTokens(params);
        mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
                mContext.getUserId());
    }

addView中 会调用

  1. 创建对应的 ViewRootImpl
  2. 将对应参数添加到各自的数组中
  3. 调用 ViewRootImplsetVIew 开始执行添加视图的 3步曲 (addToDisplayAsUser, relayout, finishDraw)
 public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow, int userId) {
        if (view == null) {
            throw new IllegalArgumentException("view must not be null");
        }
        if (display == null) {
            throw new IllegalArgumentException("display must not be null");
        }
        if (!(params instanceof WindowManager.LayoutParams)) {
            throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
        }

        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        // 如果不为空则认为子窗口添加,通过 adjustLayoutParamsForSubWindow 补全对应的参数 如title 和 token
        if (parentWindow != null) {
            parentWindow.adjustLayoutParamsForSubWindow(wparams);
        } else {
            // If there's no parent, then hardware acceleration for this view is
            // set from the application's hardware acceleration setting.
            final Context context = view.getContext();
            if (context != null
                    && (context.getApplicationInfo().flags
                            & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
                wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
            }
        }
        // 创建对应的 ViewRootImpl
        ViewRootImpl root;
        View panelParentView = null;

        synchronized (mLock) {
            // Start watching for system property changes.
            if (mSystemPropertyUpdater == null) {
                mSystemPropertyUpdater = new Runnable() {
                    @Override public void run() {
                        synchronized (mLock) {
                            for (int i = mRoots.size() - 1; i >= 0; --i) {
                                mRoots.get(i).loadSystemProperties();
                            }
                        }
                    }
                };
                SystemProperties.addChangeCallback(mSystemPropertyUpdater);
            }
            // 从 mViews 获取该view是否已添加
            int index = findViewLocked(view, false);
            if (index >= 0) {
                // 判断该view是否在移除
                if (mDyingViews.contains(view)) {
                    // Don't wait for MSG_DIE to make it's way through root's queue.
                    mRoots.get(index).doDie();
                } else {
                    throw new IllegalStateException("View " + view
                            + " has already been added to the window manager.");
                }
                // The previous removeView() had not completed executing. Now it has.
            }

            // If this is a panel window, then find the window it is being
            // attached to for future reference.
            if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                    wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
                final int count = mViews.size();
                for (int i = 0; i < count; i++) {
                    if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
                        panelParentView = mViews.get(i);
                    }
                }
            }
            // 创建viewRootImpl,该方法会通过 WindowManagerGlobal.getWindowSession() 获取session
            root = new ViewRootImpl(view.getContext(), display);

            view.setLayoutParams(wparams);
            // 添加到对应的数组
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);

            // do this last because it fires off messages to start doing things
            try {
                root.setView(view, wparams, panelParentView, userId);
            } catch (RuntimeException e) {
                // BadTokenException or InvalidDisplayException, clean up.
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
                throw e;
            }
        }
    }

这样完成了Activity View的加载。


http://www.kler.cn/a/553446.html

相关文章:

  • NLP指标全解
  • SpringBoot中使用 ThreadLocal 进行多线程上下文管理及其注意事项
  • Spring Scheduling Tasks+Redis实现分布式定时任务
  • CRMEB JAVA多商户外贸版演示地址
  • 【JavaScript】《JavaScript高级程序设计 (第4版) 》笔记-Chapter17-事件
  • fpga助教面试题
  • 【论文学习】RVS-FDSC:一种基于四方向条带卷积的视网膜血管分割方法以增强特征提取
  • 开源之夏经验分享|Koupleless 社区魏照华:开源精神是场永不停歇的接力
  • C++ Primer 构造函数再探
  • 【学习笔记】Cadence电子设计全流程(一)Cadence 生态及相关概念
  • 碳化硅(SiC)功率器件:新能源汽车的“心脏”革命与技术突围
  • Spotify AI 技术(1)使用 TensorFlow 和 TF-Agents
  • top命令输出内容详解
  • C++蓝桥杯基础篇(四)
  • 使用 Qt 插件和 SQLCipher 实现 SQLite 数据库加密与解密
  • Vue2和Vue3的Hooks有什么区别
  • nginx ngx_http_module(8) 指令详解
  • Starlink卫星动力学系统仿真建模番外篇6-地球敏感器
  • 【AI战略思考15】我对做自媒体视频博主的初步探索和一些思考
  • 【java基础】Java 中的 this 关键字