日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > Android >内容正文

Android

android decorview动画,Android窗口机制(二)Window,PhoneWindow,DecorView,setContentView源码理解...

發(fā)布時(shí)間:2023/12/19 Android 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android decorview动画,Android窗口机制(二)Window,PhoneWindow,DecorView,setContentView源码理解... 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Android窗口機(jī)制系列

前篇文章中出現(xiàn)了PhoneWindow,DecorView這些類,如果是第一次見(jiàn)過(guò)的話,肯定會(huì)覺(jué)得陌生。這篇文章主要跟大家講解Window,PhoneWindow,DecorView他們的理解以及他們之間的聯(lián)系

Window

我們來(lái)看下源碼里面的說(shuō)明

/**

* 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.

*/

public abstract class Window {

...

@Nullable

public View findViewById(@IdRes int id) {

return getDecorView().findViewById(id);

}

/**

* Convenience for * {@link #setContentView(View, android.view.ViewGroup.LayoutParams)}

* to set the screen content from a layout resource. The resource will be * inflated, adding all top-level views to the screen. * * @param layoutResID Resource ID to be inflated.

* @see #setContentView(View, android.view.ViewGroup.LayoutParams)

*/

public abstract void setContentView(@LayoutRes int layoutResID);

...

}

一個(gè)頂級(jí)窗口查看和行為的一個(gè)抽象基類。這個(gè)類的實(shí)例作為一個(gè)頂級(jí)View添加到Window Manager。它提供了一套標(biāo)準(zhǔn)的UI方法,比如添加背景,標(biāo)題等等。當(dāng)你需要用到Window的時(shí)候,你應(yīng)該使用它的唯一實(shí)現(xiàn)類PhoneWindow。可以看到,Window是一個(gè)抽象基類,它提供了一系列窗口的方法,比如設(shè)置背景,標(biāo)題等等,而它的唯一實(shí)現(xiàn)類則是PhoneWindow

PhoneWindow

Window的唯一實(shí)現(xiàn)類

public class PhoneWindow extends Window implements MenuBuilder.Callback {

private final static String TAG = "PhoneWindow";

...

// This is the top-level view of the window, containing the window decor.

private DecorView mDecor;

// 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.

private ViewGroup mContentParent;

private ViewGroup mContentRoot;

...

}

可以看到,在PhoneWindow里面,出現(xiàn)了成員變量DecorView的而這里,DecorView則是PhoneWindow里面的一個(gè)內(nèi)部類,它是繼承與FrameLayout

private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {

/* package */int mDefaultOpacity = PixelFormat.OPAQUE;

/** The feature ID of the panel, or -1 if this is the application's DecorView */

private final int mFeatureId;

private final Rect mDrawingBounds = new Rect();

private final Rect mBackgroundPadding = new Rect();

private final Rect mFramePadding = new Rect();

private final Rect mFrameOffsets = new Rect();

....

}

既然是FrameLayout,也就可以加載布局文件,也就是說(shuō),我們那些標(biāo)題欄,內(nèi)容欄,頂級(jí)上看是加載在DecorView上的。而DecorView則是由PhoneWindow負(fù)責(zé)添加

兩者關(guān)系以及setContentView源碼流程

接下我們就從一個(gè)常見(jiàn)的方法中去認(rèn)知他們之間的關(guān)系,那就是activity里面的setContentView,就是我們平常把布局內(nèi)容顯示到界面上的一個(gè)方法。點(diǎn)擊activity.setContentView時(shí)

public void setContentView(@LayoutRes int layoutResID) {

getWindow().setContentView(layoutResID);

initWindowDecorActionBar();

}

里面方法調(diào)用了getWindow().setContentView,而這個(gè)getWindow方法獲取的就是Activity上的Window

/**

* Retrieve the current {@link android.view.Window} for the activity.

* This can be used to directly access parts of the Window API that

* are not available through Activity/Screen.

*

* @return Window The current window, or null if the activity is not

* visual.

*/

public Window getWindow() {

return mWindow;

}

可以看到如果當(dāng)前mWindow為null的話,則表示當(dāng)前Activity不在窗口上,這里的mWindow.setContentView,實(shí)際上調(diào)用到的是它的實(shí)現(xiàn)類方法phoneWindow.setContentView

@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) {

//創(chuàng)建DecorView,并添加到mContentParent上

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 {

//將要加載的資源添加到mContentParent上

mLayoutInflater.inflate(layoutResID, mContentParent);

}

mContentParent.requestApplyInsets();

final Callback cb = getCallback();

if (cb != null && !isDestroyed()) {

//回調(diào)通知表示完成界面加載

cb.onContentChanged();

}

}

如果當(dāng)前內(nèi)容還未放置到窗口,此時(shí)mContentParent==null,也就是第一次調(diào)用的時(shí)候,調(diào)用那個(gè)installDecor方法。FEATURE_CONTENT_TRANSITIONS,則是標(biāo)記當(dāng)前內(nèi)容加載有沒(méi)有使用過(guò)度動(dòng)畫(huà),也就是轉(zhuǎn)場(chǎng)動(dòng)畫(huà)。如果內(nèi)容已經(jīng)加載過(guò),并且不需要?jiǎng)赢?huà),則會(huì)調(diào)用removeAllViews。添加完Content后如有設(shè)置了FEATURE_CONTENT_TRANSITIONS則添加Scene來(lái)過(guò)度啟動(dòng)。否則mLayoutInflater.inflate(layoutResID, mContentParent);將我們的資源文件通過(guò)LayoutInflater對(duì)象轉(zhuǎn)換為View樹(shù),并且添加至mContentParent視圖中。既然是第一次啟動(dòng)則會(huì)調(diào)用到installDecor,從字面上看可以知道該方法用來(lái)添加DecorView,看下里面說(shuō)明

private void installDecor() {

if (mDecor == null) {

//調(diào)用該方法創(chuàng)建new一個(gè)DecorView

mDecor = generateDecor();

mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);

mDecor.setIsRootNamespace(true);

if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {

mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);

}

}

//一開(kāi)始DecorView未加載到mContentParent,所以此時(shí)mContentParent=null

if (mContentParent == null) {

//該方法將mDecorView添加到Window上綁定布局

mContentParent = generateLayout(mDecor);

// Set up decor part of UI to ignore fitsSystemWindows if appropriate.

mDecor.makeOptionalFitsSystemWindows();

final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(

R.id.decor_content_parent);

...//添加其他資源

...//設(shè)置轉(zhuǎn)場(chǎng)動(dòng)畫(huà)

}

}

可以看到該方法,先通過(guò)吊桶generateDecor創(chuàng)建DecorView

protected DecorView generateDecor() {

return new DecorView(getContext(), -1);

}

創(chuàng)建完后再通過(guò)調(diào)用generateLayout將setContentView的內(nèi)容賦值到mContentParent,這個(gè)方法有點(diǎn)長(zhǎng),我們看下

protected ViewGroup generateLayout(DecorView decor) {

// Apply data from current theme.

//根據(jù)當(dāng)前設(shè)置的主題來(lái)加載默認(rèn)布局

TypedArray a = getWindowStyle();

//如果你在theme中設(shè)置了window_windowNoTitle,則這里會(huì)調(diào)用到,其他方法同理,

//這里是根據(jù)你在theme中的設(shè)置去設(shè)置的

if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {

requestFeature(FEATURE_NO_TITLE);

} else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {

// Don't allow an action bar if there is no title.

requestFeature(FEATURE_ACTION_BAR);

}

//是否有設(shè)置全屏

if (a.getBoolean(R.styleable.Window_windowFullscreen, false)) {

setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags()));

}

...//省略其他加載資源

// 添加布局到DecorView,前面說(shuō)到,DecorView是繼承與FrameLayout,它本身也是一個(gè)ViewGroup,而我們前面創(chuàng)建它的時(shí)候,只是調(diào)用了new DecorView,此時(shí)里面并無(wú)什么東西。而下面的步奏則是根據(jù)用戶設(shè)置的Feature來(lái)創(chuàng)建相應(yīng)的默認(rèn)布局主題。舉個(gè)例子,如果我在setContentView之前調(diào)用了requestWindowFeature(Window.FEATURE_NO_TITLE),這里則會(huì)通過(guò)getLocalFeatures來(lái)獲取你設(shè)置的feature,進(jìn)而選擇加載對(duì)應(yīng)的布局,此時(shí)則是加載沒(méi)有標(biāo)題欄的主題,對(duì)應(yīng)的就是R.layout.screen_simple

int layoutResource;

int features = getLocalFeatures();

// System.out.println("Features: 0x" + Integer.toHexString(features));

if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {

layoutResource = R.layout.screen_swipe_dismiss;

} ... //省略其他判斷方法

} else {

// Embedded, so no decoration is needed.

layoutResource = R.layout.screen_simple;

// System.out.println("Simple!");

}

mDecor.startChanging();

//選擇對(duì)應(yīng)布局創(chuàng)建添加到DecorView中

View in = mLayoutInflater.inflate(layoutResource, null);

decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));

mContentRoot = (ViewGroup) in;

ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);

...

return contentParent;

}

首先generateLayout會(huì)根據(jù)當(dāng)前用戶設(shè)置的主題去設(shè)置對(duì)應(yīng)的Feature,接著,根據(jù)對(duì)應(yīng)的Feature來(lái)選擇加載對(duì)應(yīng)的布局文件,(Window.FEATURE_NO_TITLE)接下來(lái)通過(guò)getLocalFeatures來(lái)獲取你設(shè)置的feature,進(jìn)而選擇加載對(duì)應(yīng)的布局,這也就是為什么我們要在setContentView之前調(diào)用requesetFeature的原因。此時(shí)則是加載沒(méi)有標(biāo)題欄的主題,對(duì)應(yīng)的就是R.layout.screen_simple,我們看下里面的布局

android:layout_width="match_parent"

android:layout_height="match_parent"

android:fitsSystemWindows="true"

android:orientation="vertical">

android:inflatedId="@+id/action_mode_bar"

android:layout="@layout/action_mode_bar"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:theme="?attr/actionBarTheme" />

android:id="@android:id/content"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:foregroundInsidePadding="false"

android:foregroundGravity="fill_horizontal|top"

android:foreground="?android:attr/windowContentOverlay" />

可以看到是LinearLayout里面包含了兩個(gè),因?yàn)樵O(shè)置可NoTitle,所以上面只有一個(gè)ViewStub,否則還有一個(gè)FrameLayout。也證明前面第一篇中說(shuō)的,“DecorView只有一個(gè)子元素為L(zhǎng)inearLayout。代表整個(gè)Window界面,包含通知欄,標(biāo)題欄,內(nèi)容顯示欄三塊區(qū)域。”注意FrameLayout里面的id,@android:id/content ,我們setContentView的內(nèi)容就是添加到這個(gè)FrameLayout中。

generateLayout的返回是contentParent,而它的獲取則是ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);`

public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;

正是id為content的FrameLayout。之后我們setContentView則是添加在mContentParent上面了。回到前面剛開(kāi)始的方法

@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) {

//創(chuàng)建DecorView,并添加到mContentParent上

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 {

//將要加載的資源添加到mContentParent上

mLayoutInflater.inflate(layoutResID, mContentParent);

}

mContentParent.requestApplyInsets();

final Callback cb = getCallback();

if (cb != null && !isDestroyed()) {

//回調(diào)通知表示完成界面改變

cb.onContentChanged();

}

}

此時(shí)已經(jīng)創(chuàng)建完DecorView并且獲取到mContentParent,接著就是將你setContentView的內(nèi)容添加到mContentParent中,也就是

mLayoutInflater.inflate(layoutResID, mContentParent);

或者

mContentParent.addView(view, params);

最后調(diào)用Callback來(lái)通知界面發(fā)生改變。Callback是Window里面的一個(gè)接口,里面聲明了當(dāng)界面更改觸摸時(shí)調(diào)用的各種方法。這里的話,我們看下onContentChanged,在PhoneWindow里面并沒(méi)有看到onContentChanged的實(shí)現(xiàn)類,而我們又知道Activity本身又是加載在Window上的,我們看下Activity

public class Activity extends ContextThemeWrapper

implements LayoutInflater.Factory2,

Window.Callback, KeyEvent.Callback,

OnCreateContextMenuListener, ComponentCallbacks2,

Window.OnWindowDismissedCallback { ... }

可以看到Activity里面實(shí)現(xiàn)了Window.Callback接口而里面onContentChanged則是空的,也就是我們可以通過(guò)重寫(xiě)該方法來(lái)監(jiān)聽(tīng)布局內(nèi)容的改變了

public void onContentChanged() {

}

小結(jié)

Window是一個(gè)抽象類,提供了各種窗口操作的方法,比如設(shè)置背景標(biāo)題ContentView等等

PhoneWindow則是Window的唯一實(shí)現(xiàn)類,它里面實(shí)現(xiàn)了各種添加背景主題ContentView的方法,內(nèi)部通過(guò)DecorView來(lái)添加頂級(jí)視圖

每一個(gè)Activity上面都有一個(gè)Window,可以通過(guò)getWindow獲取

DecorView,頂級(jí)視圖,繼承與FramentLayout,setContentView則是添加在它里面的@id/content里

setContentView里面創(chuàng)建了DecorView,根據(jù)Theme,Feature添加了對(duì)應(yīng)的布局文件

當(dāng)setContentView設(shè)置顯示后會(huì)回調(diào)Activity的onContentChanged方法

回顧

再看一下前一篇文章的結(jié)構(gòu)圖,是不是就更好理解了呢。

Paste_Image.png

下一篇文章

Android窗口機(jī)制(三)Window和WindowManager的創(chuàng)建與Activity

http://www.jianshu.com/p/6afb0c17df43

總結(jié)

以上是生活随笔為你收集整理的android decorview动画,Android窗口机制(二)Window,PhoneWindow,DecorView,setContentView源码理解...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。