Activity.attach之后流程

 接着ActivityManagerService分析流程最后从一个应用启动

https://blog.csdn.net/chi_wy/article/details/80264469 

梳理一下从

......

18.ActivityThread.handleLaunchActivity() -->

19.ActivityThread.performLaunchActivity()---> 这里会收集要启动的Activity的相关信息,主要是package和component信息,然后通过ClassLoader将要启动的Activity类加载出来,并且创建了Activity,之后执行了Activity.attch方法。

20.Instrumentation.callActivityOnCreate--->

21.Activity.performCreate -->

22.Activity.onCreate()

 

接着第19步看一下在

ActivityThread.performLaunchActivity()-->Activity.attach()

1.Window 类是一个抽象类,它的唯一实现类是 PhoneWindow;

2.PhoneWindow 有一个内部类 DecorView,DecorView 是 Activity 的根 View;

3.DecorView 继承自 FramLayout;

在attach中实例化PhoneWindow

Activity.java
private Window mWindow;

    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) {
...
...
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
...
...
...
        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();
...
}

Activity的onCreate()中setContentView调用的是getWindow().setContentView()

实际调用的是PhoneWindow.setContentView()

    // This is the view in which the window contents are placed. It is either
    // mDecor itself, or a child of mDecor where the contents go.
    ViewGroup mContentParent;
    @Override
    public void setContentView(int layoutResID) {
        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
        // decor, when theme attributes and the like are crystalized. Do not check the feature
        // before this happens.
        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);
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
        mContentParentExplicitlySet = true;
    }

 如果是第一次mContentParent为空为执行installDecor, 其中主要mDecor如果为空则在generateDecor中创建

new DecorView(context, featureId, this, getAttributes());

当 DecorView 创建成功之后,接下来就是通过 generateLayout 创建 mContentParent。(mContentParent 是一个 Viewgroup 对象)

PhoneWindow.java
private void installDecor() {
        mForceDecorInstall = false;
        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);
        }
...
        if (mContentParent == null) {
//返回当前Activity的内容区域视图,即我们的布局文件显示区域mContentParent
//根据窗口的风格修饰,选择对应的修饰布局文件,并且将id为content的FrameLayout赋值给mContentParent
            mContentParent = generateLayout(mDecor);
//初始化一堆属性值
...
...
...
       }
}
PhoneWindow.java
 
protected ViewGroup generateLayout(DecorView decor) {
        TypedArray a = getWindowStyle();
...
...
        // Inflate the window decor.

        int layoutResource;
        int features = getLocalFeatures();
...
//根据设定好的features值选择不同的窗口修饰布局文件,得到layoutResource值
//然后把选中的窗口修饰布局文件添加到DecorView对象里,并且指定contentParent值
...
        mDecor.startChanging();
        mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);

        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
        if (contentParent == null) {
            throw new RuntimeException("Window couldn't find content container view");
        }
...
        // Remaining setup -- of background and title -- that only applies
        // to top-level windows.
        if (getContainer() == null) {
...
            mDecor.setWindowBackground(background);
...
            mDecor.setWindowFrame(frame);
...
            mDecor.setElevation(mElevation);
            mDecor.setClipToOutline(mClipToOutline);
...
        }
...

        mDecor.finishChanging();
 //继续一系列属性设置,然后返回contentParent
        return contentParent;
}

在 generateLayout 方法里面首先根据应用主题 style 设置一堆值进行设置,我们设置的 android:theme 属性都是在这里的 getWindowStyle 方法中获取的,而我们在代码中通过 requestWindowFeature() 设置的属性是在 getLocalFeature 方法中获取的,这也是为什么 requestWindowFeature() 代码要在 setContentView() 前面执行。
然后根据设定好的 features 值选择不同的窗口修饰布局文件,得到布局文件的 layoutResource 值,LayoutInflater 把布局的资源文件解析成 View 之后,添加到 DecorView 中,这个 View 就是 PhoneWindow 的 mContentRoot 成员变量,而 mContentParent 就是布局文件中 ID 为 @android:id/content 的 FramLayout。
再回到 setContentView 方法中,如果 Window 没有设置 FEATURE_CONTENT_TRANSITIONS 的话,就通过 LayoutInflater 把布局文件加载到 mContentParent 中。

引用链接:https://www.jianshu.com/p/a49c6e642f74

Activity 调运 setContentView 方法自身不会显示布局的,一个 Activity 的开始实际是 ActivityThread 的 main 方法,当启动 Activity 调运完 ActivityThread 的 main 方法之后,接着调用 ActivityThread 类 performLaunchActivity 来创建要启动的 Activity 组件,在创建 Activity 组件的过程中,还会为该 Activity组件创建窗口对象和视图对象;接着 Activity 组件创建完成之后,通过调用 ActivityThread 类的 handleResumeActivity 将它激活。
在 handlerResumeActivity 中调用 Activity 的 makeVisible 方法显示我们上面通过 setContentView 创建的 mDecor 视图族。

    final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
        ActivityClientRecord r = mActivities.get(token);
...
        // TODO Push resumeArgs into the activity for consideration
        r = performResumeActivity(token, clearHide, reason);
...
        if (r != null) {
            final Activity a = r.activity;
...
            // 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) {
                try {
                    willBeVisible = ActivityManager.getService().willActivityBeVisible(
                            a.getActivityToken());
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            if (r.window == null && !a.mFinished && willBeVisible) {
                r.window = r.activity.getWindow();
                View decor = r.window.getDecorView();
                decor.setVisibility(View.INVISIBLE);
//获得ViewManager []
                ViewManager wm = a.getWindowManager();
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (r.mPreserveWindow) {
                    a.mWindowAdded = true;
                    r.mPreserveWindow = false;
                    // Normally the ViewRoot sets up callbacks with the Activity
                    // in addView->ViewRootImpl#setView. If we are instead reusing
                    // the decor view we have to notify the view root that the
                    // callbacks may have changed.
                    ViewRootImpl impl = decor.getViewRootImpl();
                    if (impl != null) {
                        impl.notifyChildRebuilt();
                    }
                }
                if (a.mVisibleFromClient) {
                    if (!a.mWindowAdded) {
                        a.mWindowAdded = true;
 //把decor view对象添加到ViewManager中
                        wm.addView(decor, l);
                    } else {
                        // The activity will get a callback for this {@link LayoutParams} change
                        // earlier. However, at that time the decor will not be set (this is set
                        // in this method), so no action will be taken. This call ensures the
                        // callback occurs with the decor set.
                        a.onWindowAttributesChanged(l);
                    }
                }
...
...
            // The window is now visible if it has been added, we are not
            // simply finishing, and we are not starting another activity.
            if (!r.activity.mFinished && willBeVisible
                    && r.activity.mDecor != null && !r.hideForNow) {
...
                r.activity.mVisibleFromServer = true;
                mNumVisibleActivities++;
                if (r.activity.mVisibleFromClient) {
                    r.activity.makeVisible();
                }
            }
...
...
            // Tell the activity manager we have resumed.
            if (reallyResume) {
                try {
                    ActivityManager.getService().activityResumed(token);
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            }
...
...
        } else {
            // If an exception was thrown when trying to resume, then
            // just end this activity.
            try {
                ActivityManager.getService()
                    .finishActivity(token, Activity.RESULT_CANCELED, null,
                            Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }
    }
其中的ViewManager wm = a.getWindowManager();wm就是windowManagerImpl的实例,通过调用addView()将decor添加
frameworks/base/core/java/android/view/WindowManagerImpl.java
    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }

传入WindowManagerGlobal.java

WindowManagerGlobal.java

private final ArrayList<View> mViews = new ArrayList<View>();
private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
private final ArrayList<WindowManager.LayoutParams> mParams =
            new ArrayList<WindowManager.LayoutParams>();
//单利模式
private static WindowManagerGlobal sDefaultWindowManager;
    public static WindowManagerGlobal getInstance() {
        synchronized (WindowManagerGlobal.class) {
            if (sDefaultWindowManager == null) {
                sDefaultWindowManager = new WindowManagerGlobal();
            }
            return sDefaultWindowManager;
        }
    }
....
....
    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
...
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        ViewRootImpl root;
        View panelParentView = null;
        synchronized (mLock) {
....
....
//实例化ViewRootImpl
            root = new ViewRootImpl(view.getContext(), display);

            view.setLayoutParams(wparams);
//添加view到集合中
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
....
            // do this last because it fires off messages to start doing things
            try {
//将view添加到ViewRootImpl中去
                root.setView(view, wparams, panelParentView);
            } catch (RuntimeException e) {
....
            }
        }
    }

View 的绘制过程是由 ViewRootImpl 来完成的,ViewRootImpl的初始化和setView上一篇中讲解:https://blog.csdn.net/chi_wy/article/details/84134320

Window官方文档:Window

public abstract class Window. Abstract base class for a top-level window look and behavior policy. An instance of this class should be used as the top-level view added to the window manager. It provides standard UI policies such as a background, title area, default key processing, etc.

The only existing implementation of this abstract class is android.view.PhoneWindow, which you should instantiate when needing a Window.

释义:每一个 Activity 都持有一个 Window 对象,但是 Window 是一个抽象类,这里 Android 为 Window 提供了唯一的实现类 PhoneWindow。也就是说 Activity 中的 window 实例就是一个 PhoneWindow 对象。

但是 PhoneWindow 终究是 Window,它并不具备多少 View 相关的能力。

不过 PhoneWindow 中持有一个 Android 中非常重要的一个 View 对象 DecorView.

现在的关系就很明确了,每一个 Activity 持有一个 PhoneWindow 的对象,而一个 PhoneWindow 对象持有一个 DecorView 的实例,所以 Activity 中 View 相关的操作其实大都是通过 DecorView 来完成。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值