溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Android窗口怎么實現(xiàn)

發(fā)布時間:2023-04-18 10:35:45 來源:億速云 閱讀:127 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要介紹“Android窗口怎么實現(xiàn)”,在日常操作中,相信很多人在Android窗口怎么實現(xiàn)問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Android窗口怎么實現(xiàn)”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

對于Window的認識階段

第一階段

剛剛學習Android的時候,都聽說過一個概念,Activity代表一個界面。實際開發(fā)起來也是如此,在Activity中加載xml文件,綁定數(shù)據(jù)與view。

Activity == UI

第二階段

看了幾篇文章,接觸了Window,WMS 概念 。發(fā)現(xiàn)Activity并不是UI界面,Activity內(nèi)部持有Window對象,Window的實現(xiàn)類PhoneWindow內(nèi)部持有DecorView作為根布局,開發(fā)人員編寫的xml 會添加到DecorView中。 哦!結(jié)合對WMS粗淺的理解,WMS是窗口管理服務(wù),window不就是窗口么,可能window在創(chuàng)建完成后最終傳遞給WMS管理。 Window == UI

第三階段

之后深入到源碼中發(fā)現(xiàn)Window雖然翻譯過來是窗口,但實際上并不是真正的窗口。

理由有二:Window并沒有與WMS交互,Window沒有view管理之類的功能。

首先可以確定的是wms是系統(tǒng)窗口服務(wù),所有窗口都要與wms打交道。如果window代表的窗口,那么它或者它的唯一子類PhoneWindow,必然存在Binder機制與wms交互,然而并沒有。

既然Window沒有與wms交互,那它做了什么工作呢?

在面向?qū)ο笾校O(shè)計一個類的意義可以從它的屬性以及暴露的方法來推測。

如下是從:PhoneWindow中摘取的一些通過名字可以大概推測出作用的屬性

大部分都是關(guān)于資源的設(shè)置:狀態(tài)欄,導(dǎo)航欄,是否透明,轉(zhuǎn)場動畫,應(yīng)用主題等等

private DecorView mDecor;
private TextView mTitleView;
int mStatusBarColor = 0;
int mNavigationBarColor = 0;
private int mTitleColor = 0;
private CharSequence mTitle = null;
boolean mIsFloating;
private boolean mIsTranslucent;
private LayoutInflater mLayoutInflater;
private Transition mEnterTransition = null;
private Transition mReturnTransition = USE_DEFAULT_TRANSITION;
private int mTheme = -1;
private boolean mIsStartingWindow;

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.

頂級窗口外觀和行為策略的抽象基類。此類的實例應(yīng)用作添加到窗口管理器的頂級視圖。它提供標準的UI策略,例如背景、標題區(qū)域、默認鍵處理等。

結(jié)合window類注釋可以做出結(jié)論,Window也是一層封裝,提供通用頁面模板,并不是真正的window。

尋找真正的Window

上面討論了Window類 并不是真正的Window,只是一層封裝。系統(tǒng)提供了WindowManager 允許開發(fā)人員添加Window。

如下代碼是在Activity獲取windowManager 添加Window。為什么api是addView 。不應(yīng)該是addWindow 才對么? 難道view才是window?(下面代碼會報錯 添加系統(tǒng)window需要權(quán)限)

val wm:WindowManager =windowManager
val layoutParams = WindowManager.LayoutParams()
layoutParams.run{
		width = WindowManager.LayoutParams.WRAP_CONTENT
		height = WindowManager.LayoutParams.WRAP_CONTENT
		format = PixelFormat.TRANSLUCENT
		gravity = Gravity.STARTor Gravity.TOP
		flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
		type =
		        if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.O) WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
		else WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG
}
val view :View = LayoutInflater.from(this).inflate(R.layout.xxx,null)
wm.addView(view, layoutParams)

跟蹤源碼

WindowManager 是個接口,實現(xiàn)類為 WindowManagerImpl

WindowManagerImpl 內(nèi)部把邏輯轉(zhuǎn)發(fā)給WindowManagerGlobal

WindowManagerGlobal 調(diào)用 ViewRootImpl

ViewRootImpl 通過WindowSession 與 wms 完成進程間通信

具體方法調(diào)用流程

WindowManager.addView() —WindowManagerImpl.addView() —WindowManagerGlobal.addView() — ViewRootImpl.setView() — WindowSession.addToDisplayAsUser()

ViewRootImpl類核心邏輯如下:

WindowManager.addView() 在應(yīng)用層最終調(diào)用 ViewRootImpl.setView()

添加的View通過 WindowSession 進入 wms,方法 IWindowSession.addToDisplay 第一個參數(shù) mWindow 代表真正的window。

mWindow的實現(xiàn)類W,類型是 IWindow.Stub ,Binder對象 對其他進程暴露方法。

W類 持有ViewRootImpl ,公開的接口方法內(nèi)部調(diào)用ViewRootImpl 類。

所以 IWindowSession 是把一個Binder對象傳遞給WMS,WMS通過進程間通信操作ViewRootImpl ,ViewRootImpl 操作View

ViewRootImpl 操作的View

對應(yīng)到當前場景是 windowManager.addView() 添加的View

對應(yīng)到Activity則是PhoneWindow中DecorView

經(jīng)過這一頓分析 好像沒有確定Window的實體對象 難以捉摸。它不像一個User類,Person類那樣明晃晃的放在開發(fā)者面前。原本以為 傳遞給WMS肯定會是Window了,結(jié)果是Binder,WMS進程間通信最終操控的是View。

public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
	final W mWindow;
	View mView;
	final IWindowSession mWindowSession;
	public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
            int userId) {
			mView = view;
			res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame,
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mDisplayCutout, inputChannel,
                            mTempInsets, mTempControls);
	}
	static class W extends IWindow.Stub {
        private final WeakReference<ViewRootImpl> mViewAncestor;
        private final IWindowSession mWindowSession;
				W(ViewRootImpl viewAncestor) {
            mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
            mWindowSession = viewAncestor.mWindowSession;
        }
				....
				@Override
        public void hideInsets(@InsetsType int types, boolean fromIme) {
            final ViewRootImpl viewAncestor = mViewAncestor.get();
            if (viewAncestor != null) {
                viewAncestor.hideInsets(types, fromIme);
            }
        }
        @Override
        public void moved(int newX, int newY) {
            final ViewRootImpl viewAncestor = mViewAncestor.get();
            if (viewAncestor != null) {
                viewAncestor.dispatchMoved(newX, newY);
            }
        }
				....省略其他方法
	}
}

Window到底是什么

window是一個抽象的概念,對應(yīng)手機屏幕的一塊區(qū)域,實際是view。

View成了Window??? 什么場景下可以把View叫做Window呢?

想象一個場景:一個Activity內(nèi)有DialogA,DialogB

這個場景會創(chuàng)建三個Window,Activity一個,Dialog兩個,對應(yīng)三個xml布局。是三個抽象的Window,對應(yīng)三個具體的View,應(yīng)該叫做View樹

它們彼此之間互不影響,為DialogA添加View,不會影響到Activity和DialogB。因為它們屬于不同的Window。

這也應(yīng)該是添加Window的Api 叫做 addView() 而不是 addWidnow() 的原因。

根本就沒有具體的Window,只有具體的View,Window是抽象的。

理解了什么是Window之后,在簡單說一下添加window的Api。

View表示需要在屏幕展示的內(nèi)容

layoutParams 則是對內(nèi)容進行約束,基本的寬高,位置。

layoutParams.type 設(shè)置window類型,其實是彈窗的顯示層級。

應(yīng)用window:1 ~ 99

子window:1000 ~ 1999

系統(tǒng)window:2000~ 2999

數(shù)值越大層級越高,層級高覆蓋層級低的,一般通過常量設(shè)置,系統(tǒng)window需要申請權(quán)限

layoutParams.flags 設(shè)置Window不同場景下的邏輯,比如:

// 全屏顯示,隱藏所有的 Window 裝飾,比如在游戲、播放器中的全屏顯示 public static final int FLAG_FULLSCREEN = 0x00000400;

// 表示比FLAG_FULLSCREEN低一級,會顯示狀態(tài)欄 public static final int FLAG_FORCE_NOT_FULLSCREEN = 0x00000800;

// 當用戶的臉貼近屏幕時(比如打電話),不會去響應(yīng)此事件 public static final int FLAG_IGNORE_CHEEK_PRESSES = 0x00008000;

// 全屏顯示,隱藏所有的 Window 裝飾,比如在游戲、播放器中的全屏顯示 public static final int FLAG_FULLSCREEN = 0x00000400;

// 表示比FLAG_FULLSCREEN低一級,會顯示狀態(tài)欄 public static final int FLAG_FORCE_NOT_FULLSCREEN = 0x00000800;

// 當用戶的臉貼近屏幕時(比如打電話),不會去響應(yīng)此事件 public static final int FLAG_IGNORE_CHEEK_PRESSES = 0x00008000;

val wm:WindowManager =windowManager
val layoutParams = WindowManager.LayoutParams()
layoutParams.run{
		width = WindowManager.LayoutParams.WRAP_CONTENT
		height = WindowManager.LayoutParams.WRAP_CONTENT
		format = PixelFormat.TRANSLUCENT
		gravity = Gravity.STARTor Gravity.TOP
		x = 0
		y = 0
		flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
		type =
		        if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.O) WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
		else WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG
}
val view :View = LayoutInflater.from(this).inflate(R.layout.xxx,null)
wm.addView(view, layoutParams)

Activity-Window-View的關(guān)系

Activity是一層封裝,屏蔽復(fù)雜的系統(tǒng)實現(xiàn)細節(jié),抽象出UI生命周期,方便開發(fā)人員工作,專注于界面樣式的編寫

Window,指PhoneWindow,頁面通用模板,所有的Window都需要主題,狀態(tài)欄,導(dǎo)航欄,背景等等設(shè)置。PhoneWindow是對上述內(nèi)容的一個模板實現(xiàn)。

軟件設(shè)計中很重要的一點就是找到業(yè)務(wù)當中的 “變與不變”。 在Window體系中,一個頁面通用不變的部分交給PhoneWindow實現(xiàn)。變化的部分就是View,讓開發(fā)人員能夠自由定制。

PhoneWindow的存在也是幫Activity減輕負擔,指責單一是一個好理解并且非常有效的原則。Activity已經(jīng)非常復(fù)雜了, 設(shè)計出PhoneWindow把UI相關(guān)的代碼從Activity中剝離出去。

由了上述層層抽象封裝才有了最初學習Android時的概念,Activity == 頁面。

到此,關(guān)于“Android窗口怎么實現(xiàn)”的學習就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI