<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>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                原文出處——>[Android應用程序窗口(Activity)的運行上下文環境(Context)的創建過程分析](http://blog.csdn.net/luoshengyang/article/details/8201936) 在前文中,我們簡要介紹了Android應用程序窗口的框架。Android應用程序窗口在運行的過程中,需要訪問一些特定的資源或者類。這些特定的資源或者類構成了Android應用程序的運行上下文環境,Android應用程序窗口可以通過一個Context接口來訪問它,這個Context接口也是我們在開發應用程序時經常碰到的。在本文中,我們就將詳細分析Android應用程序窗口的運行上下文環境的創建過程。 在前面Android應用程序窗口(Activity)實現框架簡要介紹和學習計劃一文中提到,Android應用程序窗口的運行上下文環境是通過ContextImpl類來描述的,即每一個Activity組件都關聯有一個ContextImpl對象。ContextImpl類繼承了Context類,它與Activity組件的關系如圖1所示: :-: ![](https://box.kancloud.cn/39bc09288b9851ff4eb804a5a16495d5_638x456.jpg) 圖1 ContextImpl類與Activity類的關系圖 這個類圖在設計模式里面就可以稱為裝飾模式。Activity組件通過其父類ContextThemeWrapper和ContextWrapper的成員變量mBase來引用了一個ContextImpl對象,這樣,Activity組件以后就可以通過這個ContextImpl對象來執行一些具體的操作,例如,啟動Service組件、注冊廣播接收者和啟動Content Provider組件等操作。同時,ContextImpl類又通過自己的成員變量mOuterContext來引用了與它關聯的一個Activity組件,這樣,ContextImpl類也可以將一些操作轉發給Activity組件來處理。 在前面Android應用程序啟動過程源代碼分析一文中,我們已經詳細分析過一個Activity組件的啟動過程了。在這個啟動過程中,最后一步便是通過ActivityThread類的成員函數performLaunchActivity在應用程序進程中創建一個Activity實例,并且為它設置運行上下文環境,即為它創建一個ContextImpl對象。接下來,我們就從ActivityThread類的成員函數performLaunchActivity開始,分析一個Activity實例的創建過程,以便可以從中了解它的運行上下文環境的創建過程,如圖2所示: ![](https://box.kancloud.cn/e5854aa8c58401445fb9b3ccbb1ffe0f_796x886.jpg) 圖2 Android應用程序窗口的運行上下文環境的創建過程 這個過程一共分為10個步驟,接下來我們就詳細分析每一個步驟。 **Step 1. ActivityThread.performLaunchActivity** ~~~ public final class ActivityThread { ...... Instrumentation mInstrumentation; ...... private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ...... ComponentName component = r.intent.getComponent(); ...... Activity activity = null; try { java.lang.ClassLoader cl = r.packageInfo.getClassLoader(); activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); ...... } catch (Exception e) { ...... } try { Application app = r.packageInfo.makeApplication(false, mInstrumentation); ...... if (activity != null) { ContextImpl appContext = new ContextImpl(); ...... appContext.setOuterContext(activity); ...... Configuration config = new Configuration(mConfiguration); ...... activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstance, r.lastNonConfigurationChildInstances, config); ...... mInstrumentation.callActivityOnCreate(activity, r.state); ...... } ...... } catch (SuperNotCalledException e) { ...... } catch (Exception e) { ...... } return activity; } } ~~~ 這個函數定義在文件frameworks/base/core/java/android/app/ActivityThread.java中。 要啟動的Activity組件的類名保存在變量component。有了這個類名之后,函數就可以調用ActivityThread類的成員變量mInstrumentation所描述一個Instrumentation對象的成員函數newActivity來創建一個Activity組件實例了,并且保存變量activity中。Instrumentation類是用來記錄應用程序與系統的交互過程的,在接下來的Step 2中,我們再分析它的成員函數newActivity的實現。 創建好了要啟動的Activity組件實例之后,函數接下來就可以對它進行初始化了。初始化一個Activity組件實例需要一個Application對象app、一個ContextImpl對象appContext以及一個Configuration對象config,它們分別用來描述該Activity組件實例的應用程序信息、運行上下文環境以及配置信息。這里我們主要關心運行上下文環境的創建過程,即ContextImpl對象appContext的創建過程,這個過程我們在接下來的Step 4中再分析。 ContextImpl對象appContext創建完成之后,函數就會調用它的成員函數setOuterContext來將與它所關聯的Activity組件實例activity保存在它的內部。這樣,ContextImpl對象appContext以后就可以訪問與它所關聯的Activity組件的屬性或者方法。在接下來的Step 5中,我們再分析ContextImpl類的成員函數setOuterContext的實現。 接著,函數就調用Activity組件實例activity的成員函數attach來將前面所創建的ContextImpl對象appContext以及Application對象app和Configuration對象config保存在它的內部。這樣,Activity組件實例activity就可以訪問它的運行上下文環境信息了。在接下來的Step 6中,我們再分析Activity類的成員函數attach的實現。 最后,函數又通過調用ActivityThread類的成員變量mInstrumentation所描述一個Instrumentation對象的成員函數callActivityOnCreate來通知Activity組件實例activity,它已經被創建和啟動起來了。在接下來的Step 9中,我們再分析它的成員函數callActivityOnCreate的實現。 接下來,我們就分別分析Instrumentation類的成員函數newActivity、ContextImpl類的構造函數以及成員函數setOuterContext、Activity類的成員函數attach和Instrumentation類的成員函數callActivityOnCreate的實現。 **Step 2. Instrumentation.newActivity** ~~~ public class Instrumentation { ...... public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException { return (Activity)cl.loadClass(className).newInstance(); } ...... } ~~~ 這個函數定義在文件frameworks/base/core/java/android/app/Instrumentation.java中。 參數cl描述的是一個類加載器,而參數className描述的要加載的類。以className為參數來調用cl描述的是一個類加載器的成員函數loadClass,就可以得到一個Class對象。由于className描述的是一個Activity子類,因此,當函數調用前面得到的Class對象的成員函數newInstance的時候,就會創建一個Activity子類實例。這個Activity實例就是用來描述在前面Step 1中所要啟動的Activity組件的。 Activity子類實例在創建的過程,會調用父類Activity的默認構造函數,以便可以完成Activity組件的創建過程。 **Step 3. new Activity** Activity類定義在文件frameworks/base/core/java/android/app/Activity.java中,它沒有定義自己的構造函數,因此,系統就會為它提供一個默認的構造函數。一般來說,一個類的構造函數是用來初始化該類的實例的,但是,系統為Activity類提供的默認構造函數什么也不做,也就是說,Activity類實例在創建的時候,還沒有執行實質的初始化工作。這個初始化工作要等到Activity類的成員函數attach被調用的時候才會執行。在后面的Step 6中,我們就會看到Activity類的成員函數attach是如何初始化一個Activity類實例的。 這一步執行完成之后,回到前面的Step 1中,即ActivityThread類的成員函數performLaunchActivity中,接下來就會調用ContextImpl類的構造函數來創建一個ContextImpl對象,以便可以用來描述正在啟動的Activity組件的運行上下文信息。 **Step 4. new ContextImpl** ~~~ class ContextImpl extends Context { ...... private Context mOuterContext; ...... ContextImpl() { // For debug only //++sInstanceCount; mOuterContext = this; } ...... } ~~~ 這個函數定義在文件frameworks/base/core/java/android/app/ContextImpl.java中。 ContextImpl類的成員變量mOuterContext的類型為Context。當一個ContextImpl對象是用來描述一個Activity組件的運行上下文環境時,那么它的成員變量mOuterContext指向的就是該Activity組件。由于一個ContextImpl對象在創建的時候,并沒有參數用來指明它是用來描述一個Activity組件的運行上下文環境,因此,這里就暫時將它的成員變量mOuterContext指向它自己。在接下來的Step 5中,我們就會看到,一個ContextImpl對象所關聯的一個Activity組件是通過調用ContextImpl類的成員函數setOuterContext來設置的。 這一步執行完成之后,回到前面的Step 1中,即ActivityThread類的成員函數performLaunchActivity中,接下來就會調用ContextImpl類的成員函數setOuterContext來設置前面所創建一個ContextImpl對象所關聯的一個Activity組件,即正在啟動的Activity組件。 **Step 5. ContextImpl.setOuterContext** ~~~ class ContextImpl extends Context { ...... private Context mOuterContext; ...... final void setOuterContext(Context context) { mOuterContext = context; } ...... } ~~~ 這個函數定義在文件frameworks/base/core/java/android/app/ContextImpl.java中。 參數context描述的是一個正在啟動的Activity組件,ContextImpl類的成員函數setOuterContext只是簡單地將它保存在成員變量mContext中,以表明當前正在處理的一個ContextImpl對象是用來描述一個Activity組件的運行上下文環境的。 這一步執行完成之后,回到前面的Step 1中,即ActivityThread類的成員函數performLaunchActivity中,接下來就會調用Activity類的成員函數attach來初始化正在啟動的Activity組件,其中,就包括設置正在啟動的Activity組件的運行上下文環境。 **Step 6. Activity.attach** ~~~ public class Activity extends ContextThemeWrapper implements LayoutInflater.Factory, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener, ComponentCallbacks { ...... private Application mApplication; ...... /*package*/ Configuration mCurrentConfig; ...... private Window mWindow; private WindowManager mWindowManager; ...... 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) { attachBaseContext(context); mWindow = PolicyManager.makeNewWindow(this); mWindow.setCallback(this); if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) { mWindow.setSoftInputMode(info.softInputMode); } ...... mApplication = application; ...... mWindow.setWindowManager(null, mToken, mComponent.flattenToString()); ...... mWindowManager = mWindow.getWindowManager(); mCurrentConfig = config; } ...... } ~~~ 這個函數定義在文件frameworks/base/core/java/android/app/Activity.java中。 函數首先調用從父類ContextThemeWrapper繼承下來的成員函數attachBaseConext來設置運行上下文環境,即將參數context所描述的一個ContextImpl對象保存在內部。在接下來的Step 7中,我們再分析ContextThemeWrapper類的成員函數attachBaseConext的實現。 函數接下來調用PolicyManager類的靜態成員函數makeNewWindow來創建了一個PhoneWindow,并且保存在Activity類的成員變量mWindow中。這個PhoneWindow是用來描述當前正在啟動的應用程序窗口的。這個應用程序窗口在運行的過程中,會接收到一些事件,例如,鍵盤、觸摸屏事件等,這些事件需要轉發給與它所關聯的Activity組件處理,這個轉發操作是通過一個Window.Callback接口來實現的。由于Activity類實現了Window.Callback接口,因此,函數就可以將當前正在啟動的Activity組件所實現的一個Window.Callback接口設置到前面創建的一個PhoneWindow里面去,這是通過調用Window類的成員函數setCallback來實現的。 參數info指向的是一個ActivityInfo對象,用來描述當前正在啟動的Activity組件的信息。其中,這個ActivityInfo對象的成員變量softInputMode用來描述當前正在啟動的一個Activity組件是否接受軟鍵盤輸入。如果接受的話,那么它的值就不等于WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED,并且描述的是當前正在啟動的Activity組件所接受的軟鍵盤輸入模式。這個軟鍵盤輸入模式設置到前面所創建的一個PhoneWindow對象內部去,這是通過調用Window類的成員函數setSoftInputMode來實現的。 在Android系統中,每一個應用程序窗口都需要由一個窗口管理者來管理,因此,函數再接下來就會調用前面所創建的一個PhoneWindow對象從父類Window繼承下來的成員函數setWindowManager來為它設置一個合適的窗口管理者。這個窗口管理者設置完成之后,就可以通過調用Window類的成員函數getWindowManager來獲得。獲得這個窗口管理者之后,函數就將它保存在Activity類的成員變量mWindowManager中。這樣,當前正在啟動的Activity組件以后就可以通過它的成員變量mWindowManager來管理與它所關聯的窗口。 除了創建和初始化一個PhoneWindow之外,函數還會分別把參數application和config所描述的一個Application對象和一個Configuration對象保存在Activity類的成員變量mApplication和mCurrentConfig中。這樣,當前正在啟動的Activity組件就可以訪問它的應用程序信息以及配置信息。 在接下來的一篇文章中,我們再詳細分析PolicyManager類的靜態成員函數makeNewWindow,以及Window類的成員函數setCallback、setSoftInputMode和setWindowManager的實現,以便可以了解應用程序窗口的創建過程。 接下來,我們繼續分析ContextThemeWrapper類的成員函數attachBaseConext的實現,以便可以繼續了解一個應用程序窗口的運行上下文環境的設置過程。 **Step 7. ContextThemeWrapper.attachBaseConext** ~~~ public class ContextThemeWrapper extends ContextWrapper { private Context mBase; ...... @Override protected void attachBaseContext(Context newBase) { super.attachBaseContext(newBase); mBase = newBase; } ...... } ~~~ 這個函數定義在文件frameworks/base/core/java/android/view/ContextThemeWrapper.java中。 ContextThemeWrapper類用來維護一個應用程序窗口的主題,而用來描述這個應用程序窗口的運行上下文環境的一個ContextImpl對象就保存在ContextThemeWrapper類的成員函數mBase中。 ContextThemeWrapper類的成員函數attachBaseConext的實現很簡單,它首先調用父類ContextWrapper的成員函數attachBaseConext來將參數newBase所描述的一個ContextImpl對象保存到父類ContextWrapper中去,接著再將這個ContextImpl對象保存在ContextThemeWrapper類的成員變量mBase中。 接下來,我們就繼續分析ContextWrapper類的成員函數attachBaseConext的實現。 **Step 8. ContextWrapper.attachBaseConext** ~~~ public class ContextWrapper extends Context { Context mBase; ...... protected void attachBaseContext(Context base) { if (mBase != null) { throw new IllegalStateException("Base context already set"); } mBase = base; } ...... } ~~~ 這個函數定義在文件frameworks/base/core/java/android/content/ContextWrapper.java 中。 ContextWrapper類只是一個代理類,它只是簡單地封裝了對其成員變量mBase所描述的一個Context對象的操作。ContextWrapper類的成員函數attachBaseConext的實現很簡單,它只是將參數base所描述的一個ContextImpl對象保存在成員變量mBase中。這樣,ContextWrapper類就可以將它的功能交給ContextImpl類來具體實現。 這一步執行完成之后,當前正在啟動的Activity組件的運行上下文環境就設置完成了,回到前面的Step 1中,即ActivityThread類的成員函數performLaunchActivity中,接下來就會調用Instrumentation類的成員函數callActivityOnCreate來通知當前正在啟動的Activity組件,它已經創建和啟動完成了。 **Step 9. Instrumentation.callActivityOnCreate** ~~~ public class Instrumentation { ...... public void callActivityOnCreate(Activity activity, Bundle icicle) { ...... activity.onCreate(icicle); ...... } ...... } ~~~ 這個函數定義在文件frameworks/base/core/java/android/app/Instrumentation.java中。 函數主要就是調用當前正在啟動的Activity組件的成員函數onCreate,用來通知它已經成功地創建和啟動完成了。 **Step 10. Activity.onCreate** ~~~ public class Activity extends ContextThemeWrapper implements LayoutInflater.Factory, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener, ComponentCallbacks { ...... boolean mCalled; ...... /*package*/ boolean mVisibleFromClient = true; ...... protected void onCreate(Bundle savedInstanceState) { mVisibleFromClient = !mWindow.getWindowStyle().getBoolean( com.android.internal.R.styleable.Window_windowNoDisplay, false); mCalled = true; } ...... } ~~~ 這個函數定義在文件frameworks/base/core/java/android/app/Activity.java中。 一般來說,我們都是通過定義一個Activity子類來實現一個Activity組件的。重寫父類Activity的某些成員函數的時候,必須要回調父類Activity的這些成員函數。例如,當Activity子類在重寫父類Activity的成員函數onCreate時,就必須回調父類Activity的成員函數onCreate。這些成員函數被回調了之后,Activity類就會將其成員變量mCalled的值設置為true。這樣,Activity類就可以通過其成員變量mCalled來檢查其子類在重寫它的某些成員函數時,是否正確地回調了父類的這些成員函數。 Activity類的另外一個成員變量mVisibleFromClient用來描述一個應用程序窗口是否是可見的。如果是可見的,那么它的值就會等于true。當Activity類的成員函數onCreate被其子類回調時,它就會檢查對應的應用程序窗口的主題屬性android:windowNoDisplay的值是否等于true。如果等于true的話,那么就說明當前所啟動的應用程序窗口是不可見的,這時候Activity類的成員變量mVisibleFromClient的值就會被設置為false,否則的話,就會被設置為true。 Activity子類在重寫成員函數onCreate的時候,一般都會調用父類Activity的成員函數setContentView來為為當前正啟動的應用程序窗口創建視圖(View)。在接下來的文章中,我們再詳細描述應用程序窗口的視圖的創建過程。 至此,一個Activity組件的創建過程,以及它的運行上下文環境的創建過程,就分析完成了。這個過程比較簡單,我們是從中獲得以下三點信息: 1. 一個Android應用窗口的運行上下文環境是使用一個ContextImpl對象來描述的,這個ContextImpl對象會分別保存在Activity類的父類ContextThemeWrapper和ContextWrapper的成員變量mBase中,即ContextThemeWrapper類和ContextWrapper類的成員變量mBase指向的是一個ContextImpl對象。 2. Activity組件在創建過程中,即在它的成員函數attach被調用的時候,會創建一個PhoneWindow對象,并且保存在成員變量mWindow中,用來描述一個具體的Android應用程序窗口。 3. Activity組件在創建的最后,即在它的子類所重寫的成員函數onCreate中,會調用父類Activity的成員函數setContentView來創建一個Android應用程序窗口的視圖。 在接下來的兩篇文章中,我們就將會詳細描述Android應用程序窗口以及它的視圖的創建過程,敬請關注!
                  <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>

                              哎呀哎呀视频在线观看