成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

在Android系統中,一個Activity的Window創建和添加過程

移動開發 Android
addToDisplay?方法內部調用了mService的addWindow?方法,并將Session?對象本身作為第一個參數傳進去。mService?就是WMS?的實例,每一個app進程?都會對應一個Session對象用來表示app進程與WMS的通信渠道。

在Android系統中,一個Activity通常就表示一個頁面,這個頁面實際是由Window來管理的,每個Activity都對應著一個Window。Window是一個抽象類,具體實現類是PhoneWindow,對View進行管理。確切的來講是,PhoneWindow包含一個DecorView類型的成員,代表這個Window的頂層View,是一個FrameLayout。DecorView的布局結構包含兩部分:標題欄(title)和內容欄(content)。根據設置的主題不同,這兩部分也會有不同的呈現。但內容欄是一定存在的,并且id是固定的android.R.id.content。

Window的創建過程

Window的創建過程是一個涉及多個層次和組件的復雜過程。

  • 當啟動一個Activity或系統通過Intent觸發一個Activity時,這個Activity的生命周期開始。
  • onCreate()方法被調用,這是Activity生命周期中的一個重要回調。
  • 在onCreate()方法中,通常會調用setContentView()來設置Activity的布局。
  • setContentView()方法會觸發Window對象的創建。在Android中,每個Activity都與一個Window對象相關聯。
  • Window對象通常是一個PhoneWindow的實例,用于處理與窗口相關的各種功能。

Activity啟動過程在ActivityThread的performLaunchActivity方法,會調用Activity的attach方法。與Activity相關聯的Window對象就是在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, 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方法中創建了一個PhoneWindow對象,并設置回調接口Callback和WindowManager。由于Activity類實現了Window.Callback接口,當Window接收到相關的事件觸發時就會調用Activity的相應方法。Callback接口中的方法很多,有幾個是我們比較常見的,比如dispatchTouchEvent、onAttachedToWindow、onDetachedFromWindow等。

Window的添加過程

  • 與Window對象關聯的是一個DecorView。DecorView是一個特殊的ViewGroup,包含了窗口的標題欄(如果有的話)和主要內容區域。
  • DecorView的創建是在Window的創建過程中自動完成的,并且與Window對象緊密相關。
  • 通過setContentView()方法加載的布局文件(通常是XML文件)會被解析并轉換為相應的View對象。
  • 這些View對象被添加到DecorView的內容區域中,形成一個View樹。
  • 繪制的結果被渲染到屏幕上,就能看到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方法返回后,程序會調用mInstrumentation.callActivityOnCreate方法,而這個方法最終會觸發Activity的onCreate回調。而在onCreate中,會調用setContentView方法,開始Activity的Window添加過程。

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

Activity的setContentView方法內部調用的mWindow的setContentView方法,這個mWindow對象就是在attach方法中創建的PhoneWindow對象。

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是否存在,否則調用installDecor方法。這個mContentParent指的就是DecorView的內容欄。它的賦值就只有一個地方,就是在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,就先調用generateDecor方法創建DecorView。

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

DecorView對象創建之后,再判斷mContentParent對象是否存在,不存在調用generateLayout方法。

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

generateLayout會返回一個ViewGroup對象contentParent,ID_ANDROID_CONTENT就是com.android.internal.R.id.content。

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

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

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

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

執行完performLaunchActivity方法返回一個Activity的實例,接下來判斷如果創建的Activity實例不為null,就會執行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方法中,會調用performResumeActivity方法,經過層層調用最終會回調Activity的onResume方法。

handleResumeActivity中,在performResumeActivity方法執行之后,會調用Activity的makeVisible方法。

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

在makeVisible方法中,會調用WindowManager的addView方法,將DecorView正式添加到窗口中,同時DecorView設置為可見。

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

在WindowManagerImpl的addView方法內部,調用的是WindowManagerGlobal的addView方法。WindowManagerImpl通過橋接模式,將功能實現委托給了WindowManagerGlobal。WindowManagerGlobal是一個單例,說明一個進程中只有一個WindowManagerGlobal實例。每一個Window都會有一個相關聯的WindowManagerImpl實例。

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方法主要完成三個步驟:

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

最終調用了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樹被構建完成,系統會遍歷這個樹,對每個View進行測量和布局,調用requestLayout方法會觸發View層級的繪制遍歷,requestLayout方法內部會調用scheduleTraversals方法。scheduleTraversals方法實際就是View繪制過程的入口。

然后會調用mWindowSession對象的addToDisplay方法,mWindowSession的類型是IWindowSession,是一個Binder對象,用于進程間通信,IWindowSession是Client端的代理。Server端實現是Session。代碼都是運行在Activity所在的app進程,Session的addToDisplay方法則是運行在WMS所在的SystemServer進程中。

圖片圖片

@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方法內部調用了mService的addWindow方法,并將Session對象本身作為第一個參數傳進去。mService就是WMS的實例,每一個app進程都會對應一個Session對象用來表示app進程與WMS的通信渠道。WMS會用ArrayList來存放這些Session對象。WMS會為這個要添加的窗口分配Surface,并確定窗口的顯示次序,真正負責顯示界面視圖的是畫布Surface而不是窗口本身。WMS會將所管理的Surface交由SurfaceFlinger處理,SurfaceFlinger會將這些Surface混合并繪制并最終呈現到屏幕上。

責任編輯:武曉燕 來源: 沐雨花飛蝶
相關推薦

2023-03-15 09:00:43

SwiftUISlider

2015-08-06 13:44:21

swiftcocoapods

2011-07-19 17:05:22

Xcode Libary

2024-01-29 10:20:39

Obsidian鏈接

2010-01-11 17:21:26

Linux Fedor

2020-09-29 07:24:14

Python字典數據

2010-04-15 17:45:26

Oracle存儲過程

2011-03-10 10:45:47

Azure“Hello Worl

2018-09-08 09:05:00

UbuntuLinuxIP地址

2009-09-22 11:54:42

ibmdwPHP

2024-10-14 17:13:48

模塊Python編程

2012-11-21 11:48:23

i-NVMM加密密碼

2011-04-08 10:29:04

AccessMIS管理系統

2011-07-20 09:16:02

MongoDB索引稀疏索引

2020-12-16 14:29:40

終端開發shell

2022-02-10 22:34:51

對象JVM收集器

2022-03-30 08:19:12

JavaGroovy

2018-11-05 15:14:42

MySQL編程語言技術

2011-07-29 13:21:31

CTE遞歸存儲過程真分頁

2019-01-07 10:25:44

Gonimo嬰兒監視開源
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 中文字幕免费在线 | 97日日碰人人模人人澡分享吧 | 日韩欧美在线播放 | 99国产精品99久久久久久 | 成人免费影院 | 天堂在线免费视频 | 国产综合第一页 | 国产一级在线观看 | 欧美日韩国产精品一区二区 | 精品国产精品三级精品av网址 | 国产高清视频一区 | 日一区二区 | 国产精品久久99 | 日韩一区二区在线视频 | 欧美日韩综合一区 | 日韩精品在线视频免费观看 | 99久久久国产精品 | 岛国毛片在线观看 | 麻豆av一区二区三区久久 | 欧美韩一区二区 | 精品国产一区二区三区日日嗨 | 亚洲国产成人精品女人久久久野战 | 久草视频在线播放 | 91精品久久久久久久久久入口 | 欧美中文字幕一区二区三区亚洲 | 欧美成人激情 | 国产日韩欧美在线观看 | 视频一区二区三区四区五区 | 国产一区二区三区在线 | 在线看无码的免费网站 | 亚洲精品久久久一区二区三区 | 国产精品久久久久久久免费大片 | 欧美jizzhd精品欧美巨大免费 | 久久国产一区二区三区 | 精品视频久久久 | 欧美高清视频在线观看 | 成人精品| 中文字幕动漫成人 | 啪一啪| 欧美三区在线观看 | 国产精品美女久久久免费 |