亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

前言

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

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

概念如下:

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

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

窗口具有Z軸層級

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

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

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

窗口這個概念在Android中并不清晰,手機移動終端屏幕太小。很少有機會和Windows一樣一塊屏幕同時展示多個窗口。

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

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

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

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

如果沒看過源碼的同志肯定會猶豫,說到底還是移動端手機屏幕太小了,沒辦法給人直觀感性的認識窗口。

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

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

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

對于Window的認識階段

第一階段

剛剛學(xué)習(xí)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ū)ο笾?,設(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)到當(dā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;

// 當(dāng)用戶的臉貼近屏幕時(比如打電話),不會去響應(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;

// 當(dāng)用戶的臉貼近屏幕時(比如打電話),不會去響應(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ù)當(dāng)中的 “變與不變”。 在Window體系中,一個頁面通用不變的部分交給PhoneWindow實現(xiàn)。變化的部分就是View,讓開發(fā)人員能夠自由定制。

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

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

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

相關(guān)文章

最新評論