欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

結(jié)合Windows窗口深入分析Android窗口的實(shí)現(xiàn)

 更新時(shí)間:2023年04月18日 09:45:50   作者:Android技術(shù)棧  
在Android中,窗口是一個(gè)基本的圖形用戶界面元素,它提供了一個(gè)屏幕區(qū)域來放置應(yīng)用程序的用戶界面元素。窗口可以是全屏的,也可以是一個(gè)小的對(duì)話框。每個(gè)窗口都有一個(gè)特定的主題和樣式,可以根據(jù)應(yīng)用程序的需求進(jìn)行自定義

前言

從windows窗口的概念開始,通過對(duì)比去理解Android窗口體系,本文沒有深入源碼,重在理解概念

代碼都是抄來抄去,概念也是互相借鑒 ??,先看看Windows窗口的一些概念。

概念如下:

是我們使用軟件時(shí)看到的界面,包含各種各樣的控件,與用戶交互

窗口有三種類型: 系統(tǒng)窗口類,應(yīng)用程序全局窗口,應(yīng)用程序局部窗口

窗口具有Z軸層級(jí)

可以設(shè)置窗口的大小與位置

平時(shí)打開文件夾,微信,網(wǎng)易云,AndroidStudio都是打開一個(gè)窗口。

了解Android窗口的同志們可能會(huì)感覺到Windows窗口的概念好熟悉呀。

窗口這個(gè)概念在Android中并不清晰,手機(jī)移動(dòng)終端屏幕太小。很少有機(jī)會(huì)和Windows一樣一塊屏幕同時(shí)展示多個(gè)窗口。

操作也不一樣,在Windows中可以隨意對(duì) 不同窗口調(diào)整,最大化最小化,拖拽,改變尺寸,切換窗口巴拉巴拉的一頓操作。

所以Windos天生就更容易理解窗口,畢竟能夠直接操作。打開微信和網(wǎng)易云一眼就能看出 這是兩個(gè)窗口。

Windows先放一哈,視線會(huì)到Android,看一個(gè)情景,包含:Activity,Dialog,Toast。 問:圖里有幾個(gè)窗口

答:三個(gè),Activity應(yīng)用窗口,Dialog子窗口,Toast系統(tǒng)窗口。

如果沒看過源碼的同志肯定會(huì)猶豫,說到底還是移動(dòng)端手機(jī)屏幕太小了,沒辦法給人直觀感性的認(rèn)識(shí)窗口。

通過對(duì)比還是看出窗口的一些特性:

具有層級(jí)概念,在上述場景中Activity層級(jí)最低,Dialog次之,Toast最高

窗口可以設(shè)置位置大小,屏幕中的一塊區(qū)域展示內(nèi)容。只不過Activity是全屏的,不像Windows可以最大化最小化, 用戶手動(dòng)改變窗口大小,弱化了窗口的概念。

對(duì)于Window的認(rèn)識(shí)階段

第一階段

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

Activity == UI

第二階段

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

第三階段

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

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

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

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

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

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

大部分都是關(guān)于資源的設(shè)置:狀態(tài)欄,導(dǎo)航欄,是否透明,轉(zhuǎn)場動(dòng)畫,應(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.

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

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

尋找真正的Window

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

如下代碼是在Activity獲取windowManager 添加Window。為什么api是addView 。不應(yīng)該是addWindow 才對(duì)么? 難道view才是window?(下面代碼會(huì)報(bào)錯(cuò) 添加系統(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 是個(gè)接口,實(shí)現(xiàn)類為 WindowManagerImpl

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

WindowManagerGlobal 調(diào)用 ViewRootImpl

ViewRootImpl 通過WindowSession 與 wms 完成進(jìn)程間通信

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

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

ViewRootImpl類核心邏輯如下:

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

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

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

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

所以 IWindowSession 是把一個(gè)Binder對(duì)象傳遞給WMS,WMS通過進(jìn)程間通信操作ViewRootImpl ,ViewRootImpl 操作View

ViewRootImpl 操作的View

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

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

經(jīng)過這一頓分析 好像沒有確定Window的實(shí)體對(duì)象 難以捉摸。它不像一個(gè)User類,Person類那樣明晃晃的放在開發(fā)者面前。原本以為 傳遞給WMS肯定會(huì)是Window了,結(jié)果是Binder,WMS進(jìn)程間通信最終操控的是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是一個(gè)抽象的概念,對(duì)應(yīng)手機(jī)屏幕的一塊區(qū)域,實(shí)際是view。

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

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

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

它們彼此之間互不影響,為DialogA添加View,不會(huì)影響到Activity和DialogB。因?yàn)樗鼈儗儆诓煌腤indow。

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

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

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

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

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

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

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

子window:1000 ~ 1999

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

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

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

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

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

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

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

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

// 當(dāng)用戶的臉貼近屏幕時(shí)(比如打電話),不會(huì)去響應(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)實(shí)現(xiàn)細(xì)節(jié),抽象出UI生命周期,方便開發(fā)人員工作,專注于界面樣式的編寫

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

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

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

由了上述層層抽象封裝才有了最初學(xué)習(xí)Android時(shí)的概念,Activity == 頁面。

到此這篇關(guān)于結(jié)合Windows窗口深入分析Android窗口的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Android窗口內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論