<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                我們已經知道了Activity的生命周期,如onCreate、onDestroy等,但大家是否考慮過這樣一個問題: - 如果沒有創建Activity,那么onCreate和onDestroy就沒有任何意義,可這個Activity究竟是在哪里創建的?。 第4章中的“Zygote分裂”一節已講過,Zygote在響應請求后會fork一個子進程,這個子進程是App對應的進程,它的入口函數是ActivityThread類的main函數。ActivityThread類中有一個handleLaunchActivity函數,它就是創建Activity的地方。一起來看這個函數,代碼如下所示: **ActivityThread.java** ~~~ private final voidhandleLaunchActivity(ActivityRecord r, Intent customIntent) { //①performLaunchActivity返回一個Activity Activitya = performLaunchActivity(r, customIntent); if(a != null) { r.createdConfig = new Configuration(mConfiguration); Bundle oldState = r.state; //②調用handleResumeActivity handleResumeActivity(r.token, false, r.isForward); } ...... } ~~~ handleLaunchActivity函數中列出了兩個關鍵點,下面對其分別介紹。 1. 創建Activity 第一個關鍵函數performLaunchActivity返回一個Activity,這個Activity就是App中的那個Activity(僅考慮App中只有一個Activity的情況),它是怎么創建的呢?其代碼如下所示: handleLaunchActivity函數中列出了兩個關鍵點,下面對其分別介紹。 **ActivityThread.java** ~~~ private final ActivityperformLaunchActivity(ActivityRecord r, Intent customIntent) { ActivityInfo aInfo = r.activityInfo; ......//完成一些準備工作 //Activity定義在Activity.java中 Activity activity = null; try { java.lang.ClassLoader cl = r.packageInfo.getClassLoader(); /* mInstrumentation為Instrumentation類型,源文件為Instrumentation.java。 它在newActivity函數中根據Activity的類名通過Java反射機制來創建對應的Activity, 這個函數比較復雜,待會我們再分析它。 */ activity = mInstrumentation.newActivity( cl,component.getClassName(), r.intent); r.intent.setExtrasClassLoader(cl); if (r.state != null) { r.state.setClassLoader(cl); } }catch (Exception e) { ...... } try { Application app = r.packageInfo.makeApplication(false,mInstrumentation); if (activity != null) { //在Activity中getContext函數返回的就是這個ContextImpl類型的對象 ContextImpl appContext = new ContextImpl(); ...... //下面這個函數會調用Activity的onCreate函數 mInstrumentation.callActivityOnCreate(activity, r.state); ...... return activity; } ~~~ 好了,performLaunchActivity函數的作用明白了吧? - 根據類名以Java反射的方法創建一個Activity。 - 調用Activity的onCreate函數,開始SDK中大書特書Activity的生命周期。 那么,在onCreate函數中,我們一般會做什么呢?在這個函數中,和UI相關的重要工作就是調用setContentView來設置UI的外觀。接下去,需要看handleLaunchActivity中第二個關鍵函數handleResumeActivity。 2. 分析handleResumeActivity 上面已創建好了一個Activity,再來看handleResumeActivity。它的代碼如下所示: **ActivityThread.java** ~~~ final void handleResumeActivity(IBinder token,boolean clearHide, boolean isForward) { boolean willBeVisible = !a.mStartedActivity; if (r.window == null && !a.mFinished&& willBeVisible) { r.window= r.activity.getWindow(); //①獲得一個View對象 Viewdecor = r.window.getDecorView(); decor.setVisibility(View.INVISIBLE); //②獲得ViewManager對象 ViewManagerwm = a.getWindowManager(); ...... //③把剛才的decor對象加入到ViewManager中 wm.addView(decor,l); } ......//其他處理 } ~~~ 上面有三個關鍵點。這些關鍵點似乎已經和UI部分(如View、Window)有聯系了。那么這些聯系是在什么時候建立的呢?在分析上面代碼中的三個關鍵點之前,請大家想想在前面的過程中,哪些地方會和UI掛上鉤呢? - 答案就在onCreate函數中,Activity一般都在這個函數中通過setContentView設置UI界面。 看來,必須先分析setContentView,才能繼續后面的征程。 3. 分析setContentView setContentView有好幾個同名函數,現在只看其中的一個就可以了。代碼如下所示: **Activity.java** ~~~ public void setContentView(View view) { //getWindow返回的是什么呢?一起來看看。 getWindow().setContentView(view); } public Window getWindow() { returnmWindow; //返回一個類型為Window的mWindow,它是什么? } ~~~ 上面出現了兩個和UI有關系的類:View和Window[①]。來看SDK文檔是怎么描述這兩個類的。這里先給出原文描述,然后進行對應翻譯: - Window:abstract base class for a top-levelwindow look and behavior policy. An instance of this class should be used asthe top-level view added to the window manager. It provides standard UIpolicies such as a background, title area, default key processing, etc. 中文的意思是:Window是一個抽象基類,用于控制頂層窗口的外觀和行為。做為頂層窗口它有什么特殊的職能呢?即繪制背景和標題欄、默認的按鍵處理等。 這里面有一句比較關鍵的話:它將做為一個頂層的view加入到Window Manager中。 - View:This class represents the basicbuilding block for user interface components. A View occupies a rectangulararea on the screen and is responsible for drawing and event handling. View的概念就比較簡單了,它是一個基本的UI單元,占據屏幕的一塊矩形區域,可用于繪制,并能處理事件。 從上面的View和Window的描述,再加上setContentView的代碼,我們能想象一下這三者的關系,如圖8-2所示: :-: ![](http://img.blog.csdn.net/20150802162126884?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖8-2 Window/View的假想關系圖 根據上面的介紹,大家可能會產生兩個疑問: - Window是一個抽象類,它實際的對象到底是什么類型? - Window Manager究竟是什么? 如果能有這樣的疑問,就說明我們非常細心了。下面試來解決這兩個問題。 (1)Activity的Window 據上文講解可知,Window是一個抽象類。它實際的對象到底屬于什么類型?先回到Activity創建的地方去看看。下面正是創建Activity時的代碼,可當時沒有深入地分析。 ~~~ activity = mInstrumentation.newActivity( cl,component.getClassName(), r.intent); ~~~ 代碼中調用了Instrumentation的newActivity,再去那里看看。 **Instrumentation.java** ~~~ public Activity newActivity(Class<?>clazz, Context context, IBinder token, Application application, Intent intent, ActivityInfo info, CharSequencetitle, Activity parent, String id,Object lastNonConfigurationInstance) throws InstantiationException, IllegalAccessException{ Activity activity = (Activity)clazz.newInstance(); ActivityThread aThread = null; //關鍵函數attach!! activity.attach(context, aThread, this, token, application, intent, info, title,parent, id, lastNonConfigurationInstance, new Configuration()); return activity; } ~~~ 看到關鍵函數attach了吧?Window的真相馬上就要揭曉了,讓我們用咆哮體②來表達內心的激動之情吧!!!! **Activity.java** ~~~ 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, Object lastNonConfigurationInstance, HashMap<String,Object> lastNonConfigurationChildInstances, Configuration config) { ...... //利用PolicyManager來創建Window對象 mWindow = PolicyManager.makeNewWindow(this); mWindow.setCallback(this); ...... //創建WindowManager對象 mWindow.setWindowManager(null, mToken, mComponent.flattenToString()); if(mParent != null) { mWindow.setContainer(mParent.getWindow()); } //保存這個WindowManager對象 mWindowManager = mWindow.getWindowManager(); mCurrentConfig = config; } ~~~ 此刻又有一點失望吧?這里冒出了個PolicyManager類,Window是由它的makeNewWindow函數所創建,因此還必須再去看看這個PolicyManager。 (2)水面下的冰山——PolicyManager PolicyManager定義于PolicyManager.java文件,該文件在一個非常獨立的目錄下,現將其單獨列出來: - frameworks/policies/base/phone/com/android/internal/policy/impl * * * * * **注意**,上面路徑中的灰色目錄phone是針對智能手機這種小屏幕的;另外還有一個平級的目錄叫mid,是針對Mid設備的。mid目錄的代碼比較少,可能目前還沒有開發完畢。 * * * * * 下面來看這個PolicyManager,它比較簡單。 **PolicyManager.java** ~~~ public final class PolicyManager { private static final String POLICY_IMPL_CLASS_NAME = "com.android.internal.policy.impl.Policy"; private static final IPolicy sPolicy; static{ // try { Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME); //創建Policy對象 sPolicy = (IPolicy)policyClass.newInstance(); }catch (ClassNotFoundException ex) { ...... } private PolicyManager() {} //通過Policy對象的makeNewWindow創建一個Window publicstatic Window makeNewWindow(Context context) { return sPolicy.makeNewWindow(context); } ...... } ~~~ 這里有一個單例的sPolicy對象,它是Policy類型,請看它的定義。 (3)真正的Window Policy類型的定義代碼如下所示: **Policy.java** ~~~ public class Policy implements IPolicy { private static final String TAG = "PhonePolicy"; private static final String[] preload_classes = { "com.android.internal.policy.impl.PhoneLayoutInflater", "com.android.internal.policy.impl.PhoneWindow", "com.android.internal.policy.impl.PhoneWindow$1", "com.android.internal.policy.impl.PhoneWindow$ContextMenuCallback", "com.android.internal.policy.impl.PhoneWindow$DecorView", "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState", "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState", }; static{ //加載所有的類 for (String s : preload_classes) { try { Class.forName(s); } catch (ClassNotFoundException ex) { ...... } } } public PhoneWindow makeNewWindow(Contextcontext) { //makeNewWindow返回的是PhoneWindow對象 return new PhoneWindow(context); } ...... } ~~~ 至此,終于知道了代碼: ~~~ mWindow = PolicyManager.makeNewWindow(this); ~~~ 返回的Window,原來是一個PhoneWindow對象。它的定義在PhoneWindow.java中。 mWindow的真實身份搞清楚了,還剩下個WindowManager。現在就來揭示其真面目。 (4)真正的WindowManager 先看WindowManager創建的代碼,如下所示: **Activity.java** ~~~ ......//創建mWindow對象 //調用mWindow的setWindowManager函數 mWindow.setWindowManager(null, mToken,mComponent.flattenToString()); ..... ~~~ 上面的函數設置了PhoneWindow的WindowManager,不過第一個參數是null,這是什么意思?在回答此問題之前,先來看PhoneWindow的定義,它是從Window類派生。 **PhoneWindow.java::PhoneWindow定義** ~~~ public class PhoneWindow extends Windowimplements MenuBuilder.Callback ~~~ 前面調用的setWindowManager函數,其實是由PhoneWindow的父類Window類來實現的,來看其代碼,如下所示: **Window.java** ~~~ public void setWindowManager(WindowManagerwm,IBinder appToken, String appName) { //注意,傳入的wm值為null mAppToken = appToken; mAppName = appName; if(wm == null) { //如果wm為空的話,則創建WindowManagerImpl對象 wm = WindowManagerImpl.getDefault(); } //mWindowManager是一個LocalWindowManager mWindowManager = new LocalWindowManager(wm); } ~~~ LocalWindowManager是在Window中定義的內部類,請看它的構造函數,其定義如下所示: **Window.java::LocalWindowManager定義** ~~~ private class LocalWindowManager implementsWindowManager { LocalWindowManager(WindowManager wm) { mWindowManager = wm;//還好,只是簡單地保存了傳入的wm參數 mDefaultDisplay = mContext.getResources().getDefaultDisplay( mWindowManager.getDefaultDisplay()); } ...... ~~~ 如上面代碼所示,LocalWindowManager將保存一個WindowManager類型的對象,這個對象的實際類型是WindowManagerImpl。而WindowManagerImpl又是什么呢?來看它的代碼,如下所示: **WindowManagerImpl.java** ~~~ public class WindowManagerImpl implementsWindowManager { ...... public static WindowManagerImpl getDefault() { return mWindowManager; //返回的就是WindowManagerImpl對象 } private static WindowManagerImpl mWindowManager= new WindowManagerImpl(); } ~~~ 看到這里,是否有點頭暈眼花?很多朋友讀我的一篇與此內容相關的博文后,普遍也有如此反應。對此,試配制了一劑治暈藥方,如圖8-3所示: :-: ![](http://img.blog.csdn.net/20150802162145510?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖8-3 Window和WindowManger的家族圖譜 根據上圖,可得出以下結論: - Activity的mWindow成員變量其真實類型是PhoneWindow,而mWindowManager成員變量的真實類型是LocalWindowManager。 - LocalWindowManager和WindowManagerImpl都實現了WindowManager接口。這里采用的是Proxy模式,表明LocalWindowManager將把它的工作委托WindowManagerImpl來完成。 (5)setContentView的總結 了解了上述知識后,重新回到setContentView函數。這次希望能分析得更深入些。 **Activity.java** ~~~ public void setContentView(View view) { getWindow().setContentView(view);//getWindow返回的是PhoneWindow } ~~~ 一起來看PhoneWindow的setContentView函數,代碼如下所示: **PhoneWindow** ~~~ public void setContentView(View view) { //調用另一個setContentView setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT,MATCH_PARENT)); } public void setContentView(View view,ViewGroup.LayoutParams params) { //mContentParent為ViewGroup類型,它的初值為null if(mContentParent == null) { installDecor(); }else { mContentParent.removeAllViews(); } //把view加入到ViewGroup中 mContentParent.addView(view, params); ...... } ~~~ mContentParent是一個ViewGroup類型,它從View中派生,所以也是一個UI單元。從它名字中“Group”所表達的意思分析,它還可以包含其他的View元素。這又是什么意思呢? - 也就是說,在繪制一個ViewGroup時,它不僅需要把自己的樣子畫出來,還需要把它包含的View元素的樣子也畫出來。讀者可將它想象成一個容器,容器中的元素就是View。 這里采用的是23種設計模式中的Composite模式,它是UI編程中常用的模式之一。 再來看installDecor函數,其代碼如下所示: **PhoneWindow.java** ~~~ private void installDecor() { if (mDecor == null) { //創建mDecor,它為DecorView類型,從FrameLayout派生 mDecor= generateDecor(); ...... } if(mContentParent == null) { //得到這個mContentParent mContentParent = generateLayout(mDecor); //創建標題欄 mTitleView= (TextView)findViewById(com.android.internal.R.id.title); ...... } ~~~ generateLayout函數的輸入參數為mDecor,輸出為mContentParent,代碼如下所示: **PhoneWindow** ~~~ protected ViewGroup generateLayout(DecorViewdecor){ ...... intlayoutResource; intfeatures = getLocalFeatures(); if((features & ((1 << FEATURE_LEFT_ICON) |(1 <<FEATURE_RIGHT_ICON))) != 0) { if(mIsFloating) { //根據情況取得對應標題欄的資源id layoutResource = com.android.internal.R.layout.dialog_title_icons; } ...... } mDecor.startChanging(); View in =mLayoutInflater.inflate(layoutResource, null); //加入標題欄 decor.addView(in,new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); /* ID_ANDROID_CONTENT的值為”com.android.internal.R.id.content” 這個contentParent由findViewById返回,實際上就是mDecorView的一部分。 */ ViewGroupcontentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); ...... mDecor.finishChanging(); returncontentParent; } ~~~ 下面看findViewById是如何實現的。它定義在Window.java中,代碼如下所示: **Window.java** ~~~ public View findViewById(int id) { //getDecorView將返回mDecorView,所以contentParent確實是DecorView的一部分 returngetDecorView().findViewById(id); } ~~~ 大家還記得圖8-2嗎?介紹完上面的知識后,根據圖8-2,可繪制更細致的圖8-4: :-: ![](http://img.blog.csdn.net/20150802162205057?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖8-4 一個Activity中的UI組件 可從上圖中看出,在Activity的onCreate函數中,通過setContentView設置的View,其實只是DecorView的子View。DecorView還處理了標題欄顯示等一系列的工作。 注意,這里使用了設計模式中的Decorator(裝飾)模式,它也是UI編程中常用的模式之一。 4. 重回handleResumeActivity 看完setContentView的分析后,不知大家是否還記得這樣一個問題:為什么要分析這個setContentView函數?在繼續前行之前,先來回顧一下被setContentView打斷的流程。 當時,我們正在分析handleResumeActivity,代碼如下所示: **ActivityThread.java** ~~~ final void handleResumeActivity(IBinder token,boolean clearHide, boolean isForward) { booleanwillBeVisible = !a.mStartedActivity; ...... if (r.window == null && !a.mFinished&& willBeVisible) { r.window= r.activity.getWindow(); //①獲得一個View對象。現在知道這個view就是DecorView Viewdecor = r.window.getDecorView(); decor.setVisibility(View.INVISIBLE); //②獲得ViewManager對象,這個wm就是LocalWindowManager ViewManagerwm = a.getWindowManager(); WindowManager.LayoutParamsl = r.window.getAttributes(); a.mDecor= decor; l.type =WindowManager.LayoutParams.TYPE_BASE_APPLICATION; if(a.mVisibleFromClient) { a.mWindowAdded= true; //③把剛才的decor對象加入到ViewManager中 wm.addView(decor,l); } ......//其他處理 } ~~~ 在上面的代碼中,由于出現了多個之前不熟悉的東西,如View、ViewManager等,而這些東西的來源又和setContentView有關,所以我們才轉而去分析setContentView了。想起來了吧? 由于代碼比較長,跳轉關系也很多,在分析代碼時,請讀者把握流程,在大腦中建立一個代碼分析的堆棧。 下面就從addView的分析開始。如前面所介紹的,它的調用方法是: ~~~ wm.addView(decor, l);//wm類型實際是LocalWindowManager ~~~ 來看這個addView函數,它的代碼如下所示: **Window.javaLocalWindowManager** ~~~ public final void addView(View view,ViewGroup.LayoutParams params) { WindowManager.LayoutParams wp =(WindowManager.LayoutParams)params; CharSequence curTitle = wp.getTitle(); ...... //做一些操作,可以不管它 //還記得前面提到過的Proxy模式嗎?mWindowManager對象實際上是WindowManagerImpl類型 mWindowManager.addView(view, params); } ~~~ 看來,要搞清楚這個addView函數還是比較麻煩的,因為現在必須到WindowManagerImpl中去看看。它的代碼如下所示: **WindowManagerImpl.java** ~~~ private void addView(View view,ViewGroup.LayoutParams params, boolean nest) { ViewRootroot; //ViewRoot,幕后的主角終于登場了! synchronized(this) { //①創建ViewRoot root =new ViewRoot(view.getContext()); root.mAddNesting = 1; view.setLayoutParams(wparams); if(mViews == null) { index = 1; mViews = new View[1]; mRoots= new ViewRoot[1]; mParams = new WindowManager.LayoutParams[1]; } else{ ...... } index--; mViews[index]= view; mRoots[index]= root;//保存這個root mParams[index]= wparams; //②setView,其中view是剛才我們介紹的DecorView root.setView(view,wparams, panelParentView);// } ~~~ “ViewRoot,ViewRoot ....”,主角終于出場了!即使沒介紹它的真實身份,不禁也想歡呼幾聲。可為避免高興得過早,還是應該先冷靜地分析一下它。這里,列出了ViewRoot的兩個重要關鍵點。 (1)ViewRoot是什么? ViewRoot是什么?看起來好像和View有些許關系,至少名字非常像。事實上,它的確和View有關系,因為它實現了ViewParent接口。SDK的文檔中有關于ViewParent的介紹。但它和Android基本繪圖單元中的View卻不太一樣,比如:ViewParent不處理繪畫,因為它沒有onDraw函數。 如上所述,ViewParent和繪畫沒有關系,那么,它的作用是什么?先來看它的代碼,如下所示: **ViewRoot.java::ViewRoot定義** ~~~ public final class ViewRoot extends Handlerimplements ViewParent, View.AttachInfo.Callbacks //從Handler類派生 { private final Surface mSurface = new Surface();//這里創建了一個Surface對象 final W mWindow; //這個是什么? View mView; } ~~~ 上面這段代碼傳達出了一些重要信息: - ViewRoot繼承了Handler類,看來它能處理消息。ViewRoot果真重寫了handleMessage函數。稍侯再來看它。 - ViewRoot有一個成員變量叫mSurface,它是Surface類型。 - ViewRoot還有一個W類型的mWindow和一個View類型的mView變量。 其中,W是ViewRoot定義的一個靜態內部類: ~~~ static class W extends IWindow.Stub ~~~ 這個類將參與Binder的通信,以后對此再做講解,先來介紹Surface類。 (2)神筆馬良乎? 這里冒出來一個Surface類。它是什么?在回答此問題之前,先來考慮這樣一個問題: - 前文介紹的View、DecorView等都是UI單元,這些UI單元的繪畫工作都在onDraw函數中完成。如果把onDraw想象成畫圖過程,那么畫布是什么? Android肯定不是“馬良”,它也沒有那支可以在任何物體上作畫的“神筆”,所以我們需要一塊實實在在的畫布,這塊畫布就是Surface。SDK文檔對Surface類的說明是:Handle on to a raw buffer thatis being managed by the screen compositor。這句話的意思是: - 有一塊Raw buffer,至于是內存還是顯存,不必管它。 - Surface操作這塊Raw buffer。 - Screen compositor(其實就是SurfaceFlinger)管理這塊Raw buffer。 Surface和SF、ViewRoot有什么關系呢?相信,聰明的你此時已經明白些了,這里用圖8-5描繪一下心中的想法: :-: ![](http://img.blog.csdn.net/20150802162116569?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖8-5 馬良的神筆工作原理 結合之前所講的知識,圖8-5清晰地傳達了如下幾條信息: - ViewRoot有一個成員變量mSurface,它是Surface類型,它和一塊Raw Buffer有關聯。 - ViewRoot是一個ViewParent,它的子View的繪畫操作,是在畫布Surface上展開的。 - Surface和SurfaceFlinger有交互,這非常類似AudioTrack和AudioFlinger之間的交互。 既然本章題目為“深入理解Surface系統”,那么就需要重點關注Surface和SurfaceFlinger間的關系。建立這個關系需ViewRoot的參與,所以應先來分析ViewRoot的創建和它的setView函數。 (3)ViewRoot的創建和對setView的分析 來分析ViewRoot的構造。關于它所包含內容,代碼如下所示: **ViewRoot.java** ~~~ public ViewRoot(Context context) { super(); .... // getWindowSession?我們進去看看 getWindowSession(context.getMainLooper()); ......//ViewRoot的mWindow是一個W類型,注意它不是Window類型,而是IWindow類型 mWindow= new W(this, context); } ~~~ getWindowsession函數,將建立Activity的ViewRoot和WindowManagerService的關系。代碼如下所示: **ViewRoot.java** ~~~ ublic static IWindowSessiongetWindowSession(Looper mainLooper) { synchronized (mStaticInit) { if(!mInitialized) { try { InputMethodManagerimm = InputMethodManager.getInstance(mainLooper); //下面這個函數先得到WindowManagerService的Binder代理,然后調用它的openSession sWindowSession = IWindowManager.Stub.asInterface( ServiceManager.getService("window")) .openSession(imm.getClient(), imm.getInputContext()); mInitialized = true; } catch (RemoteException e) { } } return sWindowSession; } } ~~~ WindowSession?WindowManagerService?第一次看到這些東西時,我快瘋了。復雜,太復雜,無比復雜!要攻克這些難題,應先來回顧一下與Zygote相關的知識: - WindowManagerService(以后簡稱WMS)由System_Server進程啟動,SurfaceFlinger服務也在這個進程中。 看來,Activity的顯示還不單純是它自己的事,還需要和WMS建立聯系才行。繼續看。先看setView的處理。這個函數很復雜, 注意其中關鍵的幾句。 openSession的操作是一個使用Binder通信的跨進程調用,暫且記住這個函數,在精簡流程之后再來分析。 代碼如下所示: **ViewRoot.java** ~~~ public void setView(View view, WindowManager.LayoutParamsattrs, View panelParentView){//第一個參數view是DecorView ...... mView= view;//保存這個view synchronized (this) { requestLayout(); //待會先看看這個。 try { //調用IWindowSession的add函數,第一個參數是mWindow res =sWindowSession.add(mWindow, mWindowAttributes, getHostVisibility(), mAttachInfo.mContentInsets); } ...... } ~~~ ViewRoot的setView函數做了三件事: - 保存傳入的view參數為mView,這個mView指向PhoneWindow的DecorView。 - 調用requestLayout。 - 調用IWindowSession的add函數,這是一個跨進程的Binder通信,第一個參數是mWindow,它是W類型,從IWindow.stub派生。 先來看這個requestLayout函數,它非常簡單,就是往handler中發送了一個消息。注意,ViewRoot是從Handler派生的,所以這個消息最后會由ViewRoot自己處理,代碼如下所示: **ViewRoot.java** ~~~ public void requestLayout() { checkThread(); mLayoutRequested = true; scheduleTraversals(); } public void scheduleTraversals() { if(!mTraversalScheduled) { mTraversalScheduled = true; sendEmptyMessage(DO_TRAVERSAL); //發送DO_TRAVERSAL消息 } } ~~~ 好,requestLayout分析完畢。 從上面的代碼中可發現,ViewRoot和遠端進程SystemServer的WMS有交互,先來總結一下它和WMS的交互流程: - ViewRoot調用openSession,得到一個IWindowSession對象。 - 調用WindowSession對象的add函數,把一個W類型的mWindow對象做為參數傳入。 5. ViewRoot和WMS的關系 上面總結了ViewRoot和WMS的交互流程,其中一共有兩個跨進程的調用。一起去看。 (1)調用流程分析 WMS的代碼在WindowManagerService.java中: **WindowManagerService.java** ~~~ public IWindowSessionopenSession(IInputMethodClient client, IInputContextinputContext) { ...... return new Session(client, inputContext); } ~~~ Session是WMS定義的內部類。它支持Binder通信,并且屬于Bn端,即響應請求的服務端。 再來看它的add函數。代碼如下所示: **WindowManagerService.java::Session** ~~~ public int add(IWindow window,WindowManager.LayoutParams attrs, int viewVisibility, Rect outContentInsets) { //調用外部類對象的addWindow,也就是WMS的addWindow returnaddWindow(this, window, attrs, viewVisibility, outContentInsets); } ~~~ **WindowManagerService.java** ~~~ public int addWindow(Session session, IWindowclient, WindowManager.LayoutParams attrs, int viewVisibility, Rect outContentInsets) { ...... //創建一個WindowState win = new WindowState(session, client, token, attachedWindow, attrs,viewVisibility); ...... //調用attach函數 win.attach(); ...... return res; } ~~~ WindowState類也是在WMS中定義的內部類,直接看它的attach函數,代碼如下所示: **WMS.java::WindowState** ~~~ void attach() { //mSession就是Session對象,調用它的windowAddedLocked函數 mSession.windowAddedLocked(); } ~~~ **WMS.java::Session** ~~~ void windowAddedLocked() { if(mSurfaceSession == null) { ...... //創建一個SurfaceSession對象 mSurfaceSession= new SurfaceSession(); ...... } mNumWindow++; } ~~~ 這里出現了另外一個重要的對象SurfaceSession。在講解它之前,急需理清一下現有的知識點,否則可能會頭暈。 (2)ViewRoot和WMS的關系梳理 ViewRoot和WMS之間的關系,可用圖8-6來表示: :-: 圖8-6 ViewRoot和WMS的關系 總結一下圖8-6中的知識點: - ViewRoot通過IWindowSession和WMS進程進行跨進程通信。IWindowSession定義在IWindowSession.aidl文件中。這個文件在編譯時由aidl工具處理,最后會生成類似于Native Binder中Bn端和Bp端的代碼,后文會介紹它。 - ViewRoot內部有一個W類型的對象,它也是一個基于Binder通信的類,W是IWindow的Bn端,用于響應請求。IWindow定義在另一個aidl文件IWindow.aidl中。 為什么需要這兩個特殊的類呢?簡單介紹一下: 首先,來看IWindowSession.aidl對自己的描述: - System private per-application interface to the window manager:也就是說每個App進程都會和WMS建立一個IWindowSession會話。這個會話被App進程用于和WMS通信。后面會介紹它的requestLayout函數。 再看對IWindow.adil的描述: - API back to a client window that the Window Manager uses to informit of interesting things happening:這句話的大意是IWindow是WMS用來做事件通知的。每當發生一些事情時,WMS就會把這些事告訴某個IWindow。可以把IWindow想象成一個回調函數。 IWindow的描述表達了什么意思呢?不妨看看它的內容,代碼如下所示: **IWindow.aidl定義** ~~~ void dispatchKey(in KeyEvent event); void dispatchPointer(in MotionEvent event, longeventTime, boolean callWhenDone); void dispatchTrackball(in MotionEvent event,long eventTime, boolean callWhenDone); ~~~ 明白了?這里的事件指的就是按鍵、觸屏等事件。那么,一個按鍵事件是如何被分發的呢?下面是它大致的流程: - WMS所在的SystemServer進程接收到按鍵事件。 - WMS找到UI位于屏幕頂端的進程所對應的IWindow對象,這是一個Bp端對象。 - 調用這個IWindow對象的dispatchKey。IWindow對象的Bn端位于ViewRoot中,ViewRoot再根據內部View的位置信息找到真正處理這個事件的View,最后調用dispatchKey函數完成按鍵的處理。 其實這些按鍵事件的分發機制可以拿Windows的UI編程來做類比,在Windows中應用程序的按鍵處理流程是: - 每一個按鍵事件都會轉化成一個消息,這個消息將由系統加入到對應進程的消息隊列中。該進程的消息在派發處理時,會根據消息的句柄找到對應的Window(窗口),繼而該消息就由這個Window處理了。 * * * * * **注意**:上面的描述實際上大大簡化了真實的處理流程,讀者可在了解大體知識后進行更深入的研究。 * * * * * 上面介紹的是ViewRoot和WMS的交互,但是我們最關心的Surface還沒有正式介紹,在此之前,還是先介紹Activity的流程。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看