自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

在Android系統(tǒng)中,一個(gè)Activity的Window創(chuàng)建和添加過程

移動(dòng)開發(fā) Android
addToDisplay?方法內(nèi)部調(diào)用了mService的addWindow?方法,并將Session?對(duì)象本身作為第一個(gè)參數(shù)傳進(jìn)去。mService?就是WMS?的實(shí)例,每一個(gè)app進(jìn)程?都會(huì)對(duì)應(yīng)一個(gè)Session對(duì)象用來表示app進(jìn)程與WMS的通信渠道。

在Android系統(tǒng)中,一個(gè)Activity通常就表示一個(gè)頁(yè)面,這個(gè)頁(yè)面實(shí)際是由Window來管理的,每個(gè)Activity都對(duì)應(yīng)著一個(gè)Window。Window是一個(gè)抽象類,具體實(shí)現(xiàn)類是PhoneWindow,對(duì)View進(jìn)行管理。確切的來講是,PhoneWindow包含一個(gè)DecorView類型的成員,代表這個(gè)Window的頂層View,是一個(gè)FrameLayout。DecorView的布局結(jié)構(gòu)包含兩部分:標(biāo)題欄(title)和內(nèi)容欄(content)。根據(jù)設(shè)置的主題不同,這兩部分也會(huì)有不同的呈現(xiàn)。但內(nèi)容欄是一定存在的,并且id是固定的android.R.id.content。

Window的創(chuàng)建過程

Window的創(chuàng)建過程是一個(gè)涉及多個(gè)層次和組件的復(fù)雜過程。

  • 當(dāng)啟動(dòng)一個(gè)Activity或系統(tǒng)通過Intent觸發(fā)一個(gè)Activity時(shí),這個(gè)Activity的生命周期開始。
  • onCreate()方法被調(diào)用,這是Activity生命周期中的一個(gè)重要回調(diào)。
  • 在onCreate()方法中,通常會(huì)調(diào)用setContentView()來設(shè)置Activity的布局。
  • setContentView()方法會(huì)觸發(fā)Window對(duì)象的創(chuàng)建。在Android中,每個(gè)Activity都與一個(gè)Window對(duì)象相關(guān)聯(lián)。
  • Window對(duì)象通常是一個(gè)PhoneWindow的實(shí)例,用于處理與窗口相關(guān)的各種功能。

Activity啟動(dòng)過程在ActivityThread的performLaunchActivity方法,會(huì)調(diào)用Activity的attach方法。與Activity相關(guān)聯(lián)的Window對(duì)象就是在attach方法中創(chuàng)建的。

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, IBinder assistToken) {
    attachBaseContext(context);
    ...
    mWindow = new PhoneWindow(this, window, activityConfigCallback);
    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);
    }
    ...
    mWindow.setWindowManager(
            (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
            mToken, mComponent.flattenToString(),
            (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
     ...

    mWindow.setColorMode(info.colorMode);
}

在attach方法中創(chuàng)建了一個(gè)PhoneWindow對(duì)象,并設(shè)置回調(diào)接口Callback和WindowManager。由于Activity類實(shí)現(xiàn)了Window.Callback接口,當(dāng)Window接收到相關(guān)的事件觸發(fā)時(shí)就會(huì)調(diào)用Activity的相應(yīng)方法。Callback接口中的方法很多,有幾個(gè)是我們比較常見的,比如dispatchTouchEvent、onAttachedToWindow、onDetachedFromWindow等。

Window的添加過程

  • 與Window對(duì)象關(guān)聯(lián)的是一個(gè)DecorView。DecorView是一個(gè)特殊的ViewGroup,包含了窗口的標(biāo)題欄(如果有的話)和主要內(nèi)容區(qū)域。
  • DecorView的創(chuàng)建是在Window的創(chuàng)建過程中自動(dòng)完成的,并且與Window對(duì)象緊密相關(guān)。
  • 通過setContentView()方法加載的布局文件(通常是XML文件)會(huì)被解析并轉(zhuǎn)換為相應(yīng)的View對(duì)象。
  • 這些View對(duì)象被添加到DecorView的內(nèi)容區(qū)域中,形成一個(gè)View樹。
  • 繪制的結(jié)果被渲染到屏幕上,就能看到Activity的界面了。

ActivityThread的performLaunchActivity方法:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
        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 (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
}

在Activity的attach方法返回后,程序會(huì)調(diào)用mInstrumentation.callActivityOnCreate方法,而這個(gè)方法最終會(huì)觸發(fā)Activity的onCreate回調(diào)。而在onCreate中,會(huì)調(diào)用setContentView方法,開始Activity的Window添加過程。

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

Activity的setContentView方法內(nèi)部調(diào)用的mWindow的setContentView方法,這個(gè)mWindow對(duì)象就是在attach方法中創(chuàng)建的PhoneWindow對(duì)象。

public void setContentView(int layoutResID) {
    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;
}

PhoneWindow的setContentView中,首先判斷mContentParent是否存在,否則調(diào)用installDecor方法。這個(gè)mContentParent指的就是DecorView的內(nèi)容欄。它的賦值就只有一個(gè)地方,就是在installDecor方法中。

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) {
        mContentParent = generateLayout(mDecor);
    ...
}

如果mDecor為null,就先調(diào)用generateDecor方法創(chuàng)建DecorView。

protected DecorView generateDecor(int featureId) {
    ...
    return new DecorView(context, featureId, this, getAttributes());
}

DecorView對(duì)象創(chuàng)建之后,再判斷mContentParent對(duì)象是否存在,不存在調(diào)用generateLayout方法。

protected ViewGroup generateLayout(DecorView decor) {
    ...
    ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
    ...
    return contentParent;
}

generateLayout會(huì)返回一個(gè)ViewGroup對(duì)象contentParent,ID_ANDROID_CONTENT就是com.android.internal.R.id.content。

最后調(diào)用mLayoutInflater.inflate(layoutResID, mContentParent)方法,將Activity的布局視圖添加到mContentParent中,回調(diào)Activity的onContentChanged方法通知Activity視圖已經(jīng)發(fā)生改變。

這個(gè)時(shí)候,Activity的視圖布局還沒有顯示出來,DecorView還沒有被WindowManager正式添加到窗口中。

在Activity執(zhí)行onResume方法之后視圖才能完全顯示,并和用戶正常交互,onResume方法是在ActivityThread的handleLaunchActivity方法中回調(diào)。

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
    ...
    Activity a = performLaunchActivity(r, customIntent);
    if (a != null) {
    r.createdConfig = new Configuration(mConfiguration);
    reportSizeConfigurations(r);
    Bundle oldState = r.state;
    handleResumeActivity(r.token, false, r.isForward,
            !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
    ...
}

執(zhí)行完performLaunchActivity方法返回一個(gè)Activity的實(shí)例,接下來判斷如果創(chuàng)建的Activity實(shí)例不為null,就會(huì)執(zhí)行handleResumeActivity方法。

final void handleResumeActivity(IBinder token,
        boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
    ...
    r = performResumeActivity(token, clearHide, reason);
    if (r != null) {
        final Activity a = r.activity;
        ...
        if (r.activity.mVisibleFromClient) {
            r.activity.makeVisible();
        }
    ...
}

在handleResumeActivity方法中,會(huì)調(diào)用performResumeActivity方法,經(jīng)過層層調(diào)用最終會(huì)回調(diào)Activity的onResume方法。

handleResumeActivity中,在performResumeActivity方法執(zhí)行之后,會(huì)調(diào)用Activity的makeVisible方法。

void makeVisible() {
    if (!mWindowAdded) {
        ViewManager wm = getWindowManager();
        wm.addView(mDecor, getWindow().getAttributes());
        mWindowAdded = true;
    }
    mDecor.setVisibility(View.VISIBLE);
}

在makeVisible方法中,會(huì)調(diào)用WindowManager的addView方法,將DecorView正式添加到窗口中,同時(shí)DecorView設(shè)置為可見。

@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyDefaultToken(params);
    mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}

在WindowManagerImpl的addView方法內(nèi)部,調(diào)用的是WindowManagerGlobal的addView方法。WindowManagerImpl通過橋接模式,將功能實(shí)現(xiàn)委托給了WindowManagerGlobal。WindowManagerGlobal是一個(gè)單例,說明一個(gè)進(jìn)程中只有一個(gè)WindowManagerGlobal實(shí)例。每一個(gè)Window都會(huì)有一個(gè)相關(guān)聯(lián)的WindowManagerImpl實(shí)例。

public void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow) {
    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;
    if (parentWindow != null) {
        parentWindow.adjustLayoutParamsForSubWindow(wparams);
    } else {
        final Context context = view.getContext();
        if (context != null
                && (context.getApplicationInfo().flags
                        & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
            wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
        }
    }
    ViewRootImpl root;
    View panelParentView = null;
    ...
        int index = findViewLocked(view, false);
        if (index >= 0) {
            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 (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);
                }
            }
        }
        root = new ViewRootImpl(view.getContext(), display);
        view.setLayoutParams(wparams);
        mViews.add(view);
        mRoots.add(root);
        mParams.add(wparams);
        try {
            root.setView(view, wparams, panelParentView);
        } catch (RuntimeException e) {
            // BadTokenException or InvalidDisplayException, clean up.
            if (index >= 0) {
                removeViewLocked(index, true);
            }
            throw e;
        }
    }
}

WindowManagerGlobal的addView方法主要完成三個(gè)步驟:

  • 檢查參數(shù)是否合法,如果是子Window還需要調(diào)整一些布局參數(shù)
  • 創(chuàng)建ViewRootImpl,并將傳進(jìn)來的View添加到mViews列表里
  • 通過ViewRootImpl來更新界面并完成Window的添加過程。

最終調(diào)用了root.setView(view, wparams, panelParentView)方法。

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    ...
    requestLayout();
    ...
    try {
    mOrigWindowType = mWindowAttributes.type;
    mAttachInfo.mRecomputeGlobalAttributes = true;
    collectViewAttributes();
    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
            getHostVisibility(), mDisplay.getDisplayId(),
            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
            mAttachInfo.mOutsets, mInputChannel);
    ...
}

View樹被構(gòu)建完成,系統(tǒng)會(huì)遍歷這個(gè)樹,對(duì)每個(gè)View進(jìn)行測(cè)量和布局,調(diào)用requestLayout方法會(huì)觸發(fā)View層級(jí)的繪制遍歷,requestLayout方法內(nèi)部會(huì)調(diào)用scheduleTraversals方法。scheduleTraversals方法實(shí)際就是View繪制過程的入口。

然后會(huì)調(diào)用mWindowSession對(duì)象的addToDisplay方法,mWindowSession的類型是IWindowSession,是一個(gè)Binder對(duì)象,用于進(jìn)程間通信,IWindowSession是Client端的代理。Server端實(shí)現(xiàn)是Session。代碼都是運(yùn)行在Activity所在的app進(jìn)程,Session的addToDisplay方法則是運(yùn)行在WMS所在的SystemServer進(jìn)程中。

圖片圖片

@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
        int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
        Rect outOutsets, InputChannel outInputChannel) {
    return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
            outContentInsets, outStableInsets, outOutsets, outInputChannel);
}

addToDisplay方法內(nèi)部調(diào)用了mService的addWindow方法,并將Session對(duì)象本身作為第一個(gè)參數(shù)傳進(jìn)去。mService就是WMS的實(shí)例,每一個(gè)app進(jìn)程都會(huì)對(duì)應(yīng)一個(gè)Session對(duì)象用來表示app進(jìn)程與WMS的通信渠道。WMS會(huì)用ArrayList來存放這些Session對(duì)象。WMS會(huì)為這個(gè)要添加的窗口分配Surface,并確定窗口的顯示次序,真正負(fù)責(zé)顯示界面視圖的是畫布Surface而不是窗口本身。WMS會(huì)將所管理的Surface交由SurfaceFlinger處理,SurfaceFlinger會(huì)將這些Surface混合并繪制并最終呈現(xiàn)到屏幕上。

責(zé)任編輯:武曉燕 來源: 沐雨花飛蝶
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)