国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁 > news >正文

浙江建設(shè)職業(yè)繼續(xù)教育學(xué)院網(wǎng)站如何搭建網(wǎng)站平臺

浙江建設(shè)職業(yè)繼續(xù)教育學(xué)院網(wǎng)站,如何搭建網(wǎng)站平臺,個人博客登錄入口,青島微網(wǎng)站建設(shè)0. 相關(guān)分享 Android從屏幕刷新到View的繪制(一)之 Window、WindowManager和WindowManagerService之間的關(guān)系 Android從屏幕刷新到View的繪制(二)之Choreographer、Vsync與屏幕刷新 1. 相關(guān)類 WindowManagerService&#xff0c…

0. 相關(guān)分享

Android從屏幕刷新到View的繪制(一)之 Window、WindowManager和WindowManagerService之間的關(guān)系
Android從屏幕刷新到View的繪制(二)之Choreographer、Vsync與屏幕刷新

1. 相關(guān)類

WindowManagerService,下文簡稱WMS

這是一個系統(tǒng)服務(wù),由SystemServer啟動,運行在一個Binder線程,管理著Android系統(tǒng)中所有的Window。

這有什么實際作用呢?除了刷新View,它還可以為其他服務(wù)提供Window管理的支持,例如當(dāng)觸摸屏幕時產(chǎn)生輸入事件,InputManangerService可以通過WMS來拿到所有Window信息,找到合適的Window進行輸入事件的派發(fā),此后,Window就會把這個輸入事件傳遞給頂級View,也就是DecorView,接著就進入到熟悉的事件分發(fā)機制了。

Window

表示一個窗口的抽象的概念,這是一個空實現(xiàn)的抽象類,在APP進程中,它有實現(xiàn)類PhoneWindow。

PhoneWindow

是Window的實現(xiàn)類,一個Activity對應(yīng)著一個PhoneWindow,在PhoneWindow中有一個頂級View——DecorView

DecorView

Activity的根View,繼承自FrameLayout

ViewRootImpl

負責(zé)DecorView下所有View的調(diào)度,例如invalidate()等,Activity下的所有View都會向上找到DecorView,最終找到ViewRootImpl來處理

WindowManagerImpl

它是WindowManager接口的實現(xiàn)類,WindowManager接口又繼承自ViewManager,顧名思義它是管理View和Window關(guān)系的。ViewManager中規(guī)范了三個方法:addView(), updateViewLayout(), removeView()。這三個任務(wù)最后也交到了WindowManagerGlobal來處理

WindowManagerGlobal

它是一個單例設(shè)計,一個APP進程對應(yīng)一個WindowManagerGlobal,持有WMS的binder引用,可以通過它來與WMS進行IPC(跨進程通信)交互。

它還擁有許多集合,例如mViews包含了進程下所有View,mRoots包含了進程下所有ViewRootImpl,mDyingViews包含了進程下所有要銷毀的View。

2. 上述類間的關(guān)系圖

Window是View的載體,我們想要對Window進行添加、刪除、更新View,就要通過WindowManager,實際管理著是WindowManagerGlobal,它與WMS通過Session進行IPC通信,具體的實現(xiàn)交給了WMS處理。

VeznzR.png

WMS也會為每個WIndow創(chuàng)建一個WindowState來管理它們,具體的渲染工作交給了SurfaceFinger處理。本文只討論View、Window、WindowManager與WMS的關(guān)系。

img

3. Window對View的管理

Window是抽象的概念,它的實現(xiàn)類為PhoneWindow,內(nèi)部維護著一個DecorView,換句話說,WIndow是以View的形式呈現(xiàn)給用戶的。Window對View的操作,實際是通過ViewRootImpl實現(xiàn)。使用過程中,我們不會接觸并訪問到Window,而是通過WindowMananger來進行操作。

接下來說的Window對View的管理其實具體來說是對DecorView的管理,一個Window對應(yīng)一個DecorView。其中DecorView的創(chuàng)建、刪除,就相當(dāng)于Window的添加、刪除,所以也有的地方說,這部分的討論叫做window的創(chuàng)建、更新、刪除。

3.1 Window對View的添加

WindowManager的實現(xiàn)類是WindowManagerImpl

//WindowManagerImpl
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {applyDefaultToken(params);mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}@Override
public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {applyDefaultToken(params);mGlobal.updateViewLayout(view, params);
}@Override
public void removeView(View view) {mGlobal.removeView(view, false);
}

WindowManagerImpl將對View的添加、刪除、更新都交給了WIndowManagerGlobal,mGlobal是一個單例:

//WindowManagerGlobal
public static WindowManagerGlobal getInstance() {synchronized (WindowManagerGlobal.class) {if (sDefaultWindowManager == null) {sDefaultWindowManager = new WindowManagerGlobal();}return sDefaultWindowManager;}
}

首先我們看到WindowManagerGlobal的addView(),具體步驟大概如下:

  1. 各類數(shù)據(jù)檢查
  2. 更新mViews、mRoots等集合
  3. 創(chuàng)建一個ViewRootImpl,將要添加的view交給它
public void addView(View view, ViewGroup.LayoutParams params,Display display, Window parentWindow) {//1.數(shù)據(jù)檢查//...ViewRootImpl root;View panelParentView = null;synchronized (mLock) {//2. 更新mViews/mRoots等集合root = new ViewRootImpl(view.getContext(), display);mViews.add(view);mRoots.add(root);mParams.add(wparams);//3.把要添加的view交給ViewRootImpltry {root.setView(view, wparams, panelParentView);} catch (RuntimeException e) {//...}}
}

ViewRootImpl添加到View之后,主要做了幾件事:

  1. 調(diào)用requestLayout()異步刷新view
  2. 通過session與WMS通信,真正完成window的添加
//ViewRootImpl
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {synchronized (this) {//值維護一個view(DecorView)if (mView == null) {mView = view;int res;//1. 調(diào)用requestLayout繪制ViewrequestLayout();//...try {//通過session與WMS通信,完成window的添加res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,getHostVisibility(), mDisplay.getDisplayId(),mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,mAttachInfo.mOutsets, mInputChannel);} catch (RemoteException e) {...}//...
}

首先,requestLayout()最后通過scheduleTraversals()來申請繪制,這部分我們在屏幕繪制的部分再詳談。只需要知道發(fā)起了重繪View的請求即可。

//ViewRootImpl
@Override
public void requestLayout() {if (!mHandlingLayoutInLayoutRequest) {//檢查線程checkThread();//標志位mLayoutRequested = true;//請求繪制scheduleTraversals();}
}

當(dāng)收到允許繪制的通知的時候,最終會進入到performTraversals(),從而對DecorView自頂向下地分發(fā)繪制流程,如measure/layout/draw。

requestLayout()之后,ViewRootImpl通過session通知WMS,去完成window的添加。IWindowSession是一個Binder引用,可以通過它來與WMS通信。WMS為每個應(yīng)用創(chuàng)建一個單獨的session,這個session可以通過WindowManagerGlobal獲得。

public ViewRootImpl(Context context, Display display) {mContext = context;//實例化ViewRootImpl的時候,ViewRootImpl就從WIndowManagerGlobal中拿到了可用的sessionmWindowSession = WindowManagerGlobal.getWindowSession();...
}

看一下WindowManagerGlobal中如何提供session的:

public static IWindowSession getWindowSession() {synchronized (WindowManagerGlobal.class) {//單例,如果已經(jīng)有了,就不再創(chuàng)建了if (sWindowSession == null) {try {InputMethodManager imm = InputMethodManager.getInstance();//WMS的引用,這個是全局引用,和AMS一樣,在ServiceManager中獲取。IWindowManager windowManager = getWindowManagerService();//wms創(chuàng)建一個session交給當(dāng)前客戶端進程的WindowManagerGlobal。sWindowSession = windowManager.openSession(new IWindowSessionCallback.Stub() {@Overridepublic void onAnimatorScaleChanged(float scale) {ValueAnimator.setDurationScale(scale);}},imm.getClient(), imm.getInputContext());} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}return sWindowSession;}
}

首先我們發(fā)現(xiàn)WindowManagerGlobal首先會拿到WMS的引用,然后才通過WMS創(chuàng)建一個session,用于后續(xù)的通信。我們知道,系統(tǒng)服務(wù)由ServiceMananger管理,可以全局獲取到WMS的binder引用。但為了讓W(xué)MS知道和它通信的到底是哪個window,這久需要單獨創(chuàng)建一個session,客戶端window通過session向WMS發(fā)起通信。

我們來看一下WMS是如何處理這個openSession()請求的:

//WindowManagerService
@Override
public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,IInputContext inputContext) {//實例化了一個SessionSession session = new Session(this, callback, client, inputContext);return session;
}

Session是一個binder實體,它持有WMS的直接引用,客戶端window可以通過session來間接地通知WMS做一些操作。

獲取到session后,ViewRootImpl的setView()就進入到了最后一步:session.addToDisplay():

//Session
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,Rect outStableInsets, Rect outOutsets,DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {//mServices就是WMS,讓W(xué)MS來addWindow()return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel);
}

我們來到WMS的addWIndow()

//WindowManagerService
public int addWindow(Session session,IWindow client,...){//為session建立一個WindowState,可以通過這個WindowState來與客戶端通信。final WindowState win = new WindowState(this, session, client, token, parentWindow,appOp[0], seq, attrs, viewVisibility, session.mUid,session.mCanAddInternalSystemWindow);
}

至此,APP進程就成功將view注冊到WMS中,同時,APP進程的WindowManagerGlobal可以通過session對WMS進行binder通信,WMS也可以通過WindowState來與WindowManagerGlobal進行binder通信。

3.2 Window對View的更新

我們再看到mGlobal.updateViewLayout(view,params);

//WindowManagerGlobal
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {//1. 參數(shù)檢查if (view == null) {throw new IllegalArgumentException("view must not be null");}if (!(params instanceof WindowManager.LayoutParams)) {throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");}final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;//2.更新layoutParams以及mRoot中對應(yīng)的ViewRootImplview.setLayoutParams(wparams);synchronized (mLock) {//找到這個view對應(yīng)的ViewRootImpl是誰int index = findViewLocked(view, true);ViewRootImpl root = mRoots.get(index);mParams.remove(index);mParams.add(index, wparams);//更新ViewRootImpl,這里setLayoutParams()最后也會調(diào)用到scheduleTraversals()來請求重繪,細節(jié)不在這里討論root.setLayoutParams(wparams, false);}
}

最后到了ViewRootImpl.setLayoutParams(),最后也會調(diào)用到scheduleTraversals()來請求重繪,View的繪制、刷新的細節(jié)不在本文中討論。

3.3 WIndow對View的刪除

對View的刪除大概分為以下幾步:

  1. 首先讓ViewRootImpl用die來刪除
  2. 然后將要刪除的view記錄到mGlobal的mDyingViews集合中。
  3. View可能立即刪除 doDie(),也可能不是立即刪,就放入隊列
  4. 移除各種回調(diào)
  5. 最后通知WMS移除這個window

我們直接看到最后:

//ViewRootImpl
mWindowSession.remove(mWindow);

4. 都有哪些Window會進行這樣的創(chuàng)建、更新、刪除操作?

Activity、Dialog、Toast等都需要View,而View都需要依附于WIndow

先從簡單的Dialog對Window的創(chuàng)建談起,最后再長篇大論到Activity的Window的創(chuàng)建

4.1 Dialog 的window創(chuàng)建

Dialog的構(gòu)造方法明顯看打了PhoneWindow的實例化、WindowManager的引用(借以與WMS通信)

Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {//...//獲取windowManagermWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);//實例化PhoneWindowfinal Window w = new PhoneWindow(mContext);mWindow = w;//設(shè)置回調(diào)w.setCallback(this);w.setOnWindowDismissedCallback(this);w.setOnWindowSwipeDismissedCallback(() -> {if (mCancelable) {cancel();}});w.setWindowManager(mWindowManager, null, null);//...
}

接著來到setContentView,就是把視圖布局交給DecorView,細節(jié)我們在Activity.ssetContent()中討論,幾乎一樣的。我們再來看一下show()方法

public void show() {//...mDecor = mWindow.getDecorView();//...WindowManager.LayoutParams l = mWindow.getAttributes();boolean restoreSoftInputMode = false;if ((l.softInputMode& WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {l.softInputMode |=WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;restoreSoftInputMode = true;}//使用WindowManager.addViewmWindowManager.addView(mDecor, l);//...
}

mWindowManager.addView()我們知道最后會通過session通知到WMS,需要創(chuàng)建一個window來展示這個dialog。

4.2 長篇大論 Activity 的 Window創(chuàng)建

大概步驟如下:

  1. APP進程啟動時,會通知AMS,application啟動好了,并把applicationThread這個binder實體引用交給AMS
  2. AMS再以此通知app進程的第一個activity啟動
  3. Activity啟動之前初始化WindowManagerGlobal
  4. 最后onResume()執(zhí)行完畢后,將window的添加通知給WMS

我們直接切入重點,AMS -> ActivityStarter-> ActivityStackSupervisor->realStartActivity()->app進程->handleLaunchActivity(),在這個方法中主要調(diào)用了Activity幾個回調(diào):

  1. attach()
  2. onCreate()
  3. onStart()
  4. onResume()
//ActivityThread
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {// Initialize before creating the activityif (!ThreadedRenderer.sRendererDisabled) {GraphicsEnvironment.earlyInitEGL();}//創(chuàng)建單例,創(chuàng)建WMS引用 IWindowManagerWindowManagerGlobal.initialize();//啟動activityperformLaunchActivity();//回調(diào)onResume()handleResumeActivity();
}

Activity.attach()主要做了幾件事:

  1. 建立了一個與Activity一一對應(yīng)的PhoneWindow實例mWindow
  2. 為mWindow設(shè)置一個WMS引用
  3. Activity的mWindowManager也持有WMS引用
public class Activity implements Window.Callback,Window.OnWindowDismissedCallback,WindowControllerCallback,...{private Window mWindow;//一個Activity有一個Window,實現(xiàn)類為PhoneWindowprivate WindowManager mWindowManager;//WMS的引用final void attach(...){//一個activity對應(yīng)一個PhoneWindowmWindow = new PhoneWindow(Activit.this,window,...);//設(shè)置一些回調(diào)mWindow.setWindowControllerCallback(this);mWindow.setCallback(this);mWindow.setOnWindowDismissedCallback(this);//...//給Window設(shè)置一個WMS的引用mWindow.setWindowManager(//獲取WMS的遠程引用(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),mToken, mComponent.flattenToString(),(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);//拿到WMS的引用mWindowManager = mWindow.getWindowManager();}
}

正常情況下,我們可能會在onCreate()中調(diào)用setContentView():

public void setContentView(int layoutResId){getWindow().setContentView(layoutResId);initWindowDecorActionBar();
}

getWindow()拿到的是mWindow,實現(xiàn)類是PhoneWindow,看到它的setContentView()

//PhoneWindow
private DecorView mDecor;
private ViewGroup mContentParent;public void setContentView(int layoutResId){if(mContentParent==null){installDecor();//創(chuàng)建decorView,如果沒有的話}//...
}private void installDecor(){//1. mDecore初始化if(mDecor==null){mDecore = generateDecor(-1);//new DecoreView(phoneWindow.this)}//2. mContentParent初始化,mDecoreView下的第一個ViewGroupif (mContentParent == null) {mContentParent = generateLayout(mDecor);//根據(jù)xml屬性配置Activity的默認版型樣式}}protected ViewGroup generateLayout(DecorView decor){//...mDecor.startChanging();mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);//設(shè)置背景//...//設(shè)置title之類的mDecor.finishChanging();
}

Activity的DecorView是由PhoneWindow來管理的,包括mContentParent。最后來到handleResumeActivity(),需要注意的是:

  1. 首先回調(diào)onResume()
  2. 然后使用設(shè)置了的DecorView,或者給一個默認的DecorView,通知WMS要addView()

performResumeActivity()->Activity.performResume()->Activity.onResume()

//ActivityThread
final void handleResumeActivity(){//1.回調(diào)onResumer = performResumeActivity();//2.如果之前沒有通過setContentView()設(shè)置mDecor,則給一個默認的Activity a = r.activity;//當(dāng)前這個activityif(r.window==null){//如果activity在onResume之后還沒有mDecor,則會在這里給一個View decor = r.window.getDecorView();//如果沒有的話會PhoneWindow.installDecor()decor.setVisibility(View.INVISIBLE);//這個wm是一個WindowManager,它持有WMS的引用//WindowManager也是一個接口,實現(xiàn)類是WindowManagerImplViewManager wm = a.getWindowManager();a.mDecor = decor;if(a.mVisibleFromClient){if(!a.mWindowAdded){a.mWindowAdded= true;wm.addView(decor,l);//l:WM.LayoutParams}}   }
}

如果在onResume()結(jié)束之前,用戶都沒調(diào)用setContentView(),那么會在這里給到一個mDecor。

wm.addView(decor,l)-> WindowManagerGlobal.addView()

此后的工作我們之前就討論過了,不過是創(chuàng)建一個ViewRootImpl來維護這個DecorView,請求繪制之后通過session讓W(xué)MS來添加window。

Activity.onDestroy()時,進入到ActivityThread.handleDestroyActivity(),其中通知了WMS去removeView(),也就是移除這個Activity的Window。最后再通知AMS自己的銷毀,ActivityManager.getService().activityDestroyed();

參考文獻:

本文基于Android8.0源碼分析。結(jié)合一些博客的思路進行編排。
https://juejin.cn/post/6863756420380196877
https://blog.csdn.net/hfy8971613/article/details/103241153

http://m.aloenet.com.cn/news/42426.html

相關(guān)文章:

  • 大學(xué)生兼職網(wǎng)站開發(fā)畢設(shè)論文上海服務(wù)政策調(diào)整
  • 個人做短視頻網(wǎng)站東莞百度seo
  • 手機如何做微商城網(wǎng)站成都推廣系統(tǒng)
  • 網(wǎng)站設(shè)置了刷新限制關(guān)鍵詞代發(fā)排名首頁
  • 做國外產(chǎn)品描述的網(wǎng)站如何優(yōu)化搜索引擎的準確性
  • 重慶建設(shè)廳網(wǎng)站如何自己編寫網(wǎng)站
  • 有贊可以做獨立網(wǎng)站嗎seo網(wǎng)絡(luò)排名優(yōu)化技巧
  • 網(wǎng)站建設(shè)的技術(shù)方案模板下載做app推廣去哪找商家
  • 給網(wǎng)站怎么做tag標簽他達拉非片多少錢一盒
  • 地方電商門戶網(wǎng)站如何建設(shè)公司網(wǎng)站制作需要多少錢
  • 玄武模板網(wǎng)站制作報價怎么聯(lián)系百度推廣
  • 深圳外貿(mào)網(wǎng)站開發(fā)建設(shè)網(wǎng)絡(luò)營銷出來可以干什么工作
  • 做動態(tài)網(wǎng)站有哪些平臺關(guān)于市場營銷的100個問題
  • 網(wǎng)站管理的內(nèi)容網(wǎng)站推廣系統(tǒng)
  • wordpress加授權(quán)網(wǎng)絡(luò)優(yōu)化工程師證書
  • 做視頻小網(wǎng)站犯法嗎可口可樂營銷策劃方案
  • 做網(wǎng)站的控件新品牌推廣策略
  • 如何選擇丹陽網(wǎng)站建設(shè)百度榜單
  • 遂溪手機網(wǎng)站建設(shè)公司百度指數(shù)專業(yè)版app
  • 我想網(wǎng)關(guān)鍵詞優(yōu)化舉例
  • h網(wǎng)站建設(shè)網(wǎng)絡(luò)優(yōu)化大師手機版
  • 做企業(yè)網(wǎng)站的好處域名注冊平臺有哪些
  • photoshop網(wǎng)站視覺設(shè)計步驟seo引流什么意思
  • 山東淄博網(wǎng)站建設(shè)的公司百度快速排名化
  • 行業(yè)資訊網(wǎng)seo推廣軟件
  • 網(wǎng)頁設(shè)計實訓(xùn)報告代碼新手學(xué)seo
  • 小型公眾號開發(fā)seo網(wǎng)站推廣經(jīng)理
  • 武漢漢口做網(wǎng)站公司訊展網(wǎng)站優(yōu)化推廣
  • 湖北省建設(shè)質(zhì)量安全協(xié)會網(wǎng)站seo網(wǎng)站推廣專員招聘
  • 網(wǎng)站在阿里云備案免費數(shù)據(jù)統(tǒng)計網(wǎng)站