五月天青色头像情侣网名,国产亚洲av片在线观看18女人,黑人巨茎大战俄罗斯美女,扒下她的小内裤打屁股

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

憑啥只有Activity的context才可以啟動Dialog呢?千里馬帶你飛

2023-09-19 10:25 作者:千里馬學(xué)框架  | 我要投稿

?

背景問題導(dǎo)出

hi,粉絲朋友們: ?大家好!近期又有學(xué)員問了一個問題,這個問題其實做應(yīng)用同學(xué)肯定都有遇到過哈,問題如下:?為啥Dialog創(chuàng)建時候一定強調(diào)要使用Activity的Context,而不可以使用全局Application的context呢?這塊可以細帶著分析一下嗎?其實這個確實是個好問題哈,平時大部分同學(xué)我確定也只是知道個上面的結(jié)論,死記硬背下來了,但是作為學(xué)了千里馬的wms/ams專題課程后,這個問題相對來說應(yīng)該就不難了哈。

千里馬的wms/ams專題課程點擊這里

[1]需要同學(xué)可以+威:androidframework007

針對這個Dialog的剖析我們將按如下流程來進行剖析:

wms層面進行dumpsys分析Dialog 對于WMS課程已經(jīng)比較熟悉了同學(xué),針對這類的窗口調(diào)研肯定是需要先使用dumpsys相關(guān)命令來看看這個Dialog的情況,下面以圖庫這個界面為例子進行分析:

這里有個Dialog,那么通過dumpsys activity containers查看一下層級結(jié)構(gòu)輸出: ?#3?Task=462?type=standard?mode=fullscreen?override-mode=undefined?requested-bounds=[0,0][0,0]?bounds=[0,0][1440,2960] ?????????#0?ActivityRecord{265c566?u0?com.android.gallery3d/.app.GalleryActivity}?t462}?type=standard?mode=fullscreen?override-mode=undefined?requested-bounds=[0,0][0,0]?bounds=[0,0][1440,2960] ??????????#1?372dff?com.android.gallery3d/com.android.gallery3d.app.GalleryActivity?type=standard?mode=fullscreen?override-mode=undefined?requested-bounds=[0,0][0,0]?bounds=[0,0][1440,2960] ??????????#0?d924826?com.android.gallery3d/com.android.gallery3d.app.GalleryActivity?type=standard?mode=fullscreen?override-mode=undefined?requested-bounds=[0,0][0,0]?bounds=[0,0][1440,2960] 明顯可以看到圖庫這個ActivityRecord下面居然掛載了兩個WindowState 那么這里基本上可以判斷Dialog其實也是有自己獨立的WindowState,但是他屬于ActivityRecord下面的節(jié)點,而且Dialog的WidnowState覆蓋在Activity本身的WindowState的上面。上面信息還不夠,繼續(xù)dumpsys window windows看看window的情況: //Dialog的WindowState Window?#10?Window{372dff?u0?com.android.gallery3d/com.android.gallery3d.app.GalleryActivity}: ????mDisplayId=0?rootTaskId=462?mSession=Session{812e805?1834:u0a10083}?mClient=android.os.BinderProxy@8bce11e ????mOwnerUid=10083?showForAllUsers=false?package=com.android.gallery3d?appop=NONE ????mAttrs={(0,0)(wrapxwrap)?gr=CENTER?sim={adjust=pan?forwardNavigation}?ty=APPLICATION?fmt=TRANSPARENT?wanim=0x10302fb ??????fl=DIM_BEHIND?ALT_FOCUSABLE_IM?SPLIT_TOUCH?HARDWARE_ACCELERATED ??????pfl=USE_BLAST?INSET_PARENT_FRAME_BY_IME ??????bhv=DEFAULT ??????fitTypes=STATUS_BARS?NAVIGATION_BARS?CAPTION_BAR} ????Requested?w=1366?h=443?mLayoutSeq=260 ????mBaseLayer=21000?mSubLayer=0????mToken=ActivityRecord{265c566?u0?com.android.gallery3d/.app.GalleryActivity}?t462} ????mActivityRecord=ActivityRecord{265c566?u0?com.android.gallery3d/.app.GalleryActivity}?t462} ????mAppDied=false????drawnStateEvaluated=true????mightAffectAllDrawn=true ????mViewVisibility=0x0?mHaveFrame=true?mObscured=false ????mGivenContentInsets=[0,0][0,0]?mGivenVisibleInsets=[0,0][0,0] ????mFullConfiguration={1.0?310mcc260mnc?[en_US]?ldltr?sw411dp?w411dp?h797dp?560dpi?nrml?long?port?finger?qwerty/v/v?dpad/v?winConfig={?mBounds=Rect(0,?0?-?1440,?2960)?mAppBounds=Rect(0,?0?-?1440,?2876)?mMaxBounds=Rect(0,?0?-?1440,?2960)?mDisplayRotation=ROTATION_0?mWindowingMode=fullscreen?mDisplayWindowingMode=fullscreen?mActivityType=standard?mAlwaysOnTop=undefined?mRotation=ROTATION_0}?s.1?fontWeightAdjustment=0} //Activity的WindowState ??Window?#12?Window{d924826?u0?com.android.gallery3d/com.android.gallery3d.app.GalleryActivity}: ????mDisplayId=0?rootTaskId=462?mSession=Session{812e805?1834:u0a10083}?mClient=android.os.BinderProxy@6deff81 ????mOwnerUid=10083?showForAllUsers=false?package=com.android.gallery3d?appop=NONE ????mAttrs={(0,0)(fillxfill)?sim={adjust=pan?forwardNavigation}?ty=BASE_APPLICATION?fmt=TRANSLUCENT?wanim=0x10302fa ??????fl=LAYOUT_IN_SCREEN?LAYOUT_INSET_DECOR?SPLIT_TOUCH?HARDWARE_ACCELERATED ??????pfl=NO_MOVE_ANIMATION?FORCE_DRAW_STATUS_BAR_BACKGROUND?USE_BLAST?FIT_INSETS_CONTROLLED ??????bhv=DEFAULT ??????fitSides=} ????Requested?w=1440?h=2960?mLayoutSeq=260 ????mBaseLayer=21000?mSubLayer=0????mToken=ActivityRecord{265c566?u0?com.android.gallery3d/.app.GalleryActivity}?t462} ????mActivityRecord=ActivityRecord{265c566?u0?com.android.gallery3d/.app.GalleryActivity}?t462} ????mAppDied=false????drawnStateEvaluated=true????mightAffectAllDrawn=true ????mViewVisibility=0x0?mHaveFrame=true?mObscured=false ????mGivenContentInsets=[0,0][0,0]?mGivenVisibleInsets=[0,0][0,0] ????mFullConfiguration={1.0?310mcc260mnc?[en_US]?ldltr?sw411dp?w411dp?h797dp?560dpi?nrml?long?port?finger?qwerty/v/v?dpad/v?winConfig={?mBounds=Rect(0,?0?-?1440,?2960)?mAppBounds=Rect(0,?0?-?1440,?2876)?mMaxBounds=Rect(0,?0?-?1440,?2960)?mDisplayRotation=ROTATION_0?mWindowingMode=fullscreen?mDisplayWindowingMode=fullscreen?mActivityType=standard?mAlwaysOnTop=undefined?mRotation=ROTATION_0}?s.1?fontWeightAdjustment=0} ?? 經(jīng)過上面的dumpsys信息可以得出以下結(jié)論差異:

1 Dialog的WindowState在Activiyt的WindowState上面,所以Dialog蓋在上面? 2 Dialog的window type是APPLICATION,但是Activity的是BASE_APPLICATION 3 他們有一個共同的mToken=ActivityRecord{265c566 u0 com.android.gallery3d/.app.GalleryActivity} t462} 所以這里有了以上信息就可以得出如下結(jié)論:

1、Dialog屬于一個單獨一個Window窗口,和Activity是獨立的,二者在wms端都有獨立的WindowState? 2、Dilaog會和Activity有共同的token,有了這個一樣token加上type為APPLICATION即可以決定二者都要被掛載到ActivityRecord下面 上面就是從wms層面看待這個Dialog情況,有了以上的結(jié)論后,我們再來看Dialog代碼的具體實現(xiàn)部分,那就會有明確目標了,因為你已經(jīng)從wms原理上剖析了Dialog情況,看源碼時候大部分都要向這個結(jié)論上靠,那樣整個上下流程我們就貫通了。那么針對Dialog,就可以重點抓token的設(shè)置,和type設(shè)置即可以 我們wms課程學(xué)習(xí)時候都知道,一般要創(chuàng)建一個全局窗口一般要以下幾個步驟:

1、創(chuàng)建一個RootView,這個RootView就是真正顯示的內(nèi)容部分? 2、會調(diào)用WindowManager的addView方法,addView方法第一個參數(shù)就是上面RootView,第二個參數(shù)就是LayoutParams 真正與wms溝通最要的就是這個LayoutParams參數(shù)可以設(shè)置對應(yīng)的type和token,也就是和我們前面說的wms結(jié)論聯(lián)系上了 應(yīng)用Framework層面Dialog的源碼分析

先來看看要顯示一個Dialog的最簡單代碼: void?showDialog()?{ ?????????Dialog?d?=?new?Dialog(this); ?????????d.setTitle("Dialog?Title"); ?????????d.setContentView(R.layout.window); ?????????d.show(); ?????} 可以看到Dialog需要進行new,而且需要傳遞Context參數(shù),這里來重點看看Dialog的構(gòu)造源碼:Dialog的構(gòu)造方法有好幾個,最后都會調(diào)用到如下代碼 frameworks/base/core/java/android/app/Dialog.java Dialog(@UiContext?@NonNull?Context?context,?@StyleRes?int?themeResId, ????????????boolean?createContextThemeWrapper)?{ ????????i?????//省略部分 ????????//通過context獲取WinowManager,注意這里非常關(guān)鍵哈 ????????mWindowManager?=?(WindowManager)?context.getSystemService(Context.WINDOW_SERVICE); ????????//直接new?PhoneWindow ????????final?Window?w?=?new?PhoneWindow(mContext); ????????mWindow?=?w; ????????//省略部分 ????????//調(diào)用PhoneWindow的setWindowManager來給自己設(shè)置合適的WindowManager ????????w.setWindowManager(mWindowManager,?null,?null); ????????w.setGravity(Gravity.CENTER); ????} 這里來看看WindowManager) context.getSystemService(Context.WINDOW_SERVICE)最后其實會調(diào)用到Activity的 getSystemService,這里直接就使用了緩存的mWindowManager @Override public?Object?getSystemService(@ServiceName?@NonNull?String?name)?{ ????if?(getBaseContext()?==?null)?{ ????????throw?new?IllegalStateException( ????????????????"System?services?not?available?to?Activities?before?onCreate()"); ????} ????if?(WINDOW_SERVICE.equals(name))?{ ????????return?mWindowManager; ????}?else?if?(SEARCH_SERVICE.equals(name))?{ ????????ensureSearchManager(); ????????return?mSearchManager; ????} ????return?super.getSystemService(name); } 那么Activity的mWindowManager來自哪里,注意哈,這里我們就知道Dialog使用其實是Activity的mWindowManager。那么這個Activity的在哪里賦值?在Activity的attach方法 ??final?void?attach(Context?context,?ActivityThread?aThread, ????????????Instrumentation?instr,?IBinder?token,?int?ident, ????????????Application?application,?Intent?intent,?ActivityInfo?info, ????????????CharSequence?title,?Activity?parent,?String?id, ????????????NonConfigurationInstances?lastNonConfigurationInstances, ????????????Configuration?config,?String?referrer,?IVoiceInteractor?voiceInteractor, ????????????Window?window,?ActivityConfigCallback?activityConfigCallback,?IBinder?assistToken, ????????????IBinder?shareableActivityToken)?{ ??????? ????????mWindow.setWindowManager( ????????????????(WindowManager)context.getSystemService(Context.WINDOW_SERVICE), ????????????????mToken,?mComponent.flattenToString(), ????????????????(info.flags?&?ActivityInfo.FLAG_HARDWARE_ACCELERATED)?!=?0); ???????????????? ????????????????} 再接下來就是PhoneWindow的setWindowManager ?public?void?setWindowManager(WindowManager?wm,?IBinder?appToken,?String?appName, ????????????boolean?hardwareAccelerated)?{ ????????mAppToken?=?appToken;//設(shè)置token到了windowmanager ????????mAppName?=?appName; ????????mWindowManager?=?((WindowManagerImpl)wm).createLocalWindowManager(this); ????} 這里又調(diào)用了一個createLocalWindowManager這里其實可以認為是Activity的WindowManager要創(chuàng)建一個本地的windowmanager public?WindowManagerImpl?createLocalWindowManager(Window?parentWindow)?{ ????????return?new?WindowManagerImpl(mContext,?parentWindow,?mWindowContextToken); ????} ???private?WindowManagerImpl(Context?context,?Window?parentWindow, ????????????@Nullable?IBinder?windowContextToken)?{ ????????mContext?=?context; ????????mParentWindow?=?parentWindow; ????????mWindowContextToken?=?windowContextToken; ????} 這里的WindowManagerImpl構(gòu)造有一個變量非常關(guān)鍵parentWindow變量,一般parentWindow就是自己窗口的PhoneWindow

即這里有個結(jié)論:WindowManager的parentWindow對應(yīng)就是自己PhoneWindow

PhoneWindow其實就是繼承Window的,主要有個LayoutParams參數(shù)要注意 frameworks/base/core/java/android/view/Window.java ?private?final?WindowManager.LayoutParams?mWindowAttributes?= ????????new?WindowManager.LayoutParams(); 來看看對應(yīng)的LayoutParamas: ??public?LayoutParams()?{ ????????????super(LayoutParams.MATCH_PARENT,?LayoutParams.MATCH_PARENT); ????????????type?=?TYPE_APPLICATION;//這里初始化就是TYPE_APPLICATION ????????????format?=?PixelFormat.OPAQUE; ????????} 上面繞了一圈,其實總結(jié)如下:? 1、Dialog中的mWindowManager其實是Activiyt的,因為context是Activity 2、Dialog也有new PhoneWindow,即它將來也會成為一獨立的窗口,

這個時候type默認就是TYPE_APPLICATION

那么接下來關(guān)注重點肯定是WidnowManager的addView了,看看是否還有對LayoutParams進行相關(guān)的改變: 在Dialog第一次調(diào)用show方法時候才會進行addView ????public?void?show()?{ ?????//省略 ????????mWindowManager.addView(mDecor,?l);//注意這里mWindowManager是Activity的哈 ????? ??//省略 ????} 這里addView會一直調(diào)用到 frameworks/base/core/java/android/view/WindowManagerGlobal.java public?void?addView(View?view,?ViewGroup.LayoutParams?params, ????????????Display?display,?Window?parentWindow,?int?userId)?{ ??????? ????????final?WindowManager.LayoutParams?wparams?=?(WindowManager.LayoutParams)?params; ????????if?(parentWindow?!=?null)?{//因為是Activity的WindowManager這里的parentWindow就是activity的PhoneWindow,故不等于null ????????????parentWindow.adjustLayoutParamsForSubWindow(wparams); ????????}?else?{ ??????????? ????????} //省略 ????????????if?(windowlessSession?==?null)?{ ????????????????root?=?new?ViewRootImpl(view.getContext(),?display); ????????????}?else?{ ????????????????root?=?new?ViewRootImpl(view.getContext(),?display, ????????????????????????windowlessSession); ????????????} ????????????view.setLayoutParams(wparams); ????????????mViews.add(view); ????????????mRoots.add(root); ????????????mParams.add(wparams); ????????????//?do?this?last?because?it?fires?off?messages?to?start?doing?things ????????????try?{ ????????????????root.setView(view,?wparams,?panelParentView,?userId); ????????????}?catch?(RuntimeException?e)?{ ??????//省略 ????????} ????} 下面重點分析一下 adjustLayoutParamsForSubWindow(wparams) void?adjustLayoutParamsForSubWindow(WindowManager.LayoutParams?wp)?{ ????????CharSequence?curTitle?=?wp.getTitle(); ????????if?(wp.type?>=?WindowManager.LayoutParams.FIRST_SUB_WINDOW?&& ????????????????wp.type?<=?WindowManager.LayoutParams.LAST_SUB_WINDOW)?{ ????????????????//省略 ????????}?else?if?(wp.type?>=?WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW?&& ????????????????wp.type?<=?WindowManager.LayoutParams.LAST_SYSTEM_WINDOW)?{ ??????????????//省略 ????????}?else?{//TYPE_APPLICATION會進入這里哈 ????????????if?(wp.token?==?null)?{//前面Dialog沒有對token又過賦值為null,進入這里 ????????????????wp.token?=?mContainer?==?null???mAppToken?:?mContainer.mAppToken;//這里會是的mAppToken,它和Activity的一樣,所以就是這樣把Dialog的token和Activity的token搞成一樣的 ????????????} ????????????if?((curTitle?==?null?||?curTitle.length()?==?0) ????????????????????&&?mAppName?!=?null)?{ ????????????????wp.setTitle(mAppName); ????????????} ????????} ????????//省略 ????} 上面的這個方法就是核心關(guān)鍵,靠它把token給賦值上了,這樣在wms端就有了把Dialog和Activity搞到一起重要依據(jù)了。 總結(jié):

應(yīng)用層面的Dialog就暫時分析到這里,我們分析的思路都是基于我們已經(jīng)有了wms的較為深入的理解了,我們即可以站在更高的視角看問題,分析代碼才有目的性,不會動不動太多代碼,根本沒辦法準確分析到位,沒有目的性,很有可能那就是你分析了很久代碼,看了很多很多blog,你依然沒辦法抓到重點,你依然沒辦法串起來知識點。

憑啥只有Activity的context才可以啟動Dialog呢?千里馬帶你飛的評論 (共 條)

分享到微博請遵守國家法律
留坝县| 陵水| 虹口区| 桃园市| 达尔| 丹巴县| 蓝山县| 古交市| 阿拉善左旗| 白城市| 东丽区| 合水县| 饶平县| 红河县| 株洲县| 资中县| 松阳县| 承德县| 瑞丽市| 鹤山市| 若尔盖县| 定南县| 宁武县| 册亨县| 青阳县| 宜兰县| 崇仁县| 桃园县| 内丘县| 资中县| 宝兴县| 盐山县| 衡阳市| 英吉沙县| 莱西市| 双柏县| 宁城县| 汝南县| 邳州市| 丹江口市| 文成县|