Android應用程序窗口設計框架 一

在Android系統中,一個Activity對應一個應用程序窗口,任何一個Activity的啓動都是由AMS服務和應用程序進程相互配合來完成的。AMS服務統一調度系統中全部進程的Activity啓動,而每一個Activity的啓動過程則由其所屬進程來完成。AMS服務經過realStartActivityLocked函數來通知應用程序進程啓動某個Activity:html

frameworks\base\services\java\com\android\server\am\ ActivityStack.javajava

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
final boolean realStartActivityLocked(ActivityRecord r,
         ProcessRecord app, boolean andResume, boolean checkConfig)
         throws RemoteException {
     ...
     //系統參數發送變化,通知Activity
     if (checkConfig) {
         ①Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(mService.mConfiguration,
                 r.mayFreezeScreenLocked(app) ? r.appToken : null );
         mService.updateConfigurationLocked(config, r, false , false );
     }
     //將進程描述符設置到啓動的Activity描述符中
     r.app = app;
     app.waitingToKill = null ;
     //將啓動的Activity添加到進程啓動的Activity列表中
     int idx = app.activities.indexOf(r);
     if (idx < 0 ) {
         app.activities.add(r);
     }
     mService.updateLruProcessLocked(app, true , true );
     try {
         ...
         //通知應用程序進程加載Activity
         ②app.thread.scheduleLaunchActivity( new Intent(r.intent), r.appToken,
                 System.identityHashCode(r), r.info,
                 new Configuration(mService.mConfiguration),
                 r.compat, r.icicle, results, newIntents, !andResume,
                 mService.isNextTransitionForward(), profileFile, profileFd,
                 profileAutoStop);
         ...
     } catch (RemoteException e) {
         ...
     }
     if (mMainStack) {
         mService.startSetupActivityLocked();
     }
     return true ;
}

AMS經過realStartActivityLocked函數來調度應用程序進程啓動一個Activity,參數r爲即將啓動的Activity在AMS服務中的描述符,參數app爲Activity運行所在的應用程序進程在AMS服務中的描述符。函數經過IApplicationThread代理對象ApplicationThreadProxy通知應用程序進程啓動r對應的Activity,應用程序進程完成Activity的加載等準備工做後,AMS最後啓動該Activity。啓動Activity的建立等工做是在應用程序進程中完成的,AMS是經過IApplicationThread接口和應用程序進程通訊的。r.appToken 在AMS服務端的類型爲Token,是IApplicationToken的Binder本地對象。android

frameworks\base\core\java\android\app\ ActivityThread.javaapp

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
         ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
         Bundle state, List<resultinfo> pendingResults,
         List<intent> pendingNewIntents, boolean notResumed, boolean isForward,
         String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
     //將AMS服務傳過來的參數封裝爲ActivityClientRecord對象
     ActivityClientRecord r = new ActivityClientRecord();
     r.token = token;
     r.ident = ident;
     r.intent = intent;
     r.activityInfo = info;
     r.compatInfo = compatInfo;
     r.state = state;
     r.pendingResults = pendingResults;
     r.pendingIntents = pendingNewIntents;
     r.startsNotResumed = notResumed;
     r.isForward = isForward;
     r.profileFile = profileName;
     r.profileFd = profileFd;
     r.autoStopProfiler = autoStopProfiler;
     updatePendingConfiguration(curConfig);
     //使用異步消息方式實現Activity的啓動
     queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
}
</intent></resultinfo>

參數token從AMS服務端通過Binder傳輸到應用程序進程後,變爲IApplicationToken的Binder代理對象,類型爲IApplicationToken.Proxy,這是由於AMS和應用程序運行在不一樣的進程中。less

\

經過queueOrSendMessage函數將Binder跨進程調用轉換爲應用程序進程中的異步消息處理異步

frameworks\base\core\java\android\app\ ActivityThread.javaide

?
1
2
3
4
5
6
7
8
9
10
11
12
13
private class H extends Handler {
  public void handleMessage(Message msg) {
     switch (msg.what) {
             case LAUNCH_ACTIVITY: {
                 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart" );
                 ActivityClientRecord r = (ActivityClientRecord)msg.obj;
                 r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo);
                 handleLaunchActivity(r, null );
                 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
             } break ;
         }
     }
}  

LAUNCH_ACTIVITY消息在應用程序主線程消息循環中獲得處理,應用程序經過handleLaunchActivity函數來啓動Activity。到此AMS服務就完成了Activity的調度任務,將Activity的啓動過程徹底交給了應用程序進程來完成。函數

frameworks\base\core\java\android\app\ ActivityThread.java佈局

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
     //主線程空閒時會定時執行垃圾回收,主線程當前要完成啓動Activity的任務,所以這裏先暫停GC
     unscheduleGcIdler();
     if (r.profileFd != null ) {
         mProfiler.setProfiler(r.profileFile, r.profileFd);
         mProfiler.startProfiling();
         mProfiler.autoStopProfiler = r.autoStopProfiler;
     }
     // Make sure we are running with the most recent config.
     ①handleConfigurationChanged( null , null );
     //建立Activity
     ②Activity a = performLaunchActivity(r, customIntent);
     if (a != null ) {
         r.createdConfig = new Configuration(mConfiguration);
         Bundle oldState = r.state;
         //啓動Activity
         ③handleResumeActivity(r.token, false , r.isForward);
         ...
     } else {
         ...
     }
}

performLaunchActivity

應用程序進程經過performLaunchActivity函數將即將要啓動的Activity加載到當前進程空間來,同時爲啓動Activity作準備。post

frameworks\base\core\java\android\app\ ActivityThread.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
     ActivityInfo aInfo = r.activityInfo;
     if (r.packageInfo == null ) {
         //經過Activity所在的應用程序信息及該Activity對應的CompatibilityInfo信息從PMS服務中查詢當前Activity的包信息
         r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,Context.CONTEXT_INCLUDE_CODE);
     }
     //獲取當前Activity的組件信息
     ComponentName component = r.intent.getComponent();
     if (component == null ) {
         component = r.intent.resolveActivity(mInitialApplication.getPackageManager());
         r.intent.setComponent(component);
     }
     if (r.activityInfo.targetActivity != null ) {
         //packageName爲啓動Activity的包名,targetActivity爲Activity的類名
         component = new ComponentName(r.activityInfo.packageName,
                 r.activityInfo.targetActivity);
     }
     //經過類反射方式加載即將啓動的Activity
     Activity activity = null ;
     try {
         java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
         ①activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
         StrictMode.incrementExpectedActivityCount(activity.getClass());
         r.intent.setExtrasClassLoader(cl);
         if (r.state != null ) {
             r.state.setClassLoader(cl);
         }
     } catch (Exception e) {
         ...
     }
     try {
         //經過單例模式爲應用程序進程建立Application對象
         ②Application app = r.packageInfo.makeApplication( false , mInstrumentation);
         if (activity != null ) {
             //爲當前Activity建立上下文對象ContextImpl
             ContextImpl appContext = new ContextImpl();
             //上下文初始化
             ③appContext.init(r.packageInfo, r.token, this );
             appContext.setOuterContext(activity);
             CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
             ...
             Configuration config = new Configuration(mCompatConfiguration);
             //將當前啓動的Activity和上下文ContextImpl、Application綁定
             ④activity.attach(appContext, this , getInstrumentation(), r.token,
                     r.ident, app, r.intent, r.activityInfo, title, r.parent,
                     r.embeddedID, r.lastNonConfigurationInstances, config);
             ...
             //調用Activity的OnCreate函數
             ⑤mInstrumentation.callActivityOnCreate(activity, r.state);
             ...
             //將Activity保存到ActivityClientRecord中,ActivityClientRecord爲Activity在應用程序進程中的描述符
             r.activity = activity;
             ...
         }
         r.paused = true ;
         //ActivityThread的成員變量mActivities保存了當前應用程序進程中的全部Activity的描述符
         mActivities.put(r.token, r);
     } catch (SuperNotCalledException e) {
         ...
     }
     return activity;
}

在該函數中,首先經過PMS服務查找到即將啓動的Activity的包名信息,而後經過類反射方式建立一個該Activity實例,同時爲應用程序啓動的每個Activity建立一個LoadedApk實例對象,應用程序進程中建立的全部LoadedApk對象保存在ActivityThread的成員變量mPackages中。接着經過LoadedApk對象的makeApplication函數,使用單例模式建立Application對象,所以在android應用程序進程中有且只有一個Application實例。而後爲當前啓動的Activity建立一個ContextImpl上下文對象,並初始化該上下文,到此咱們能夠知道,啓動一個Activity須要如下對象:

1) XXActivity對象,須要啓動的Activity;

2) LoadedApk對象,每一個啓動的Activity都擁有屬於自身的LoadedApk對象;

3) ContextImpl對象,每一個啓動的Activity都擁有屬於自身的ContextImpl對象;

4) Application對象,應用程序進程中有且只有一個實例,和Activity是一對多的關係;

加載Activity類

?
1
2
3
4
5
6
public Activity newActivity(ClassLoader cl, String className,
         Intent intent)
         throws InstantiationException, IllegalAccessException,
         ClassNotFoundException {
     return (Activity)cl.loadClass(className).newInstance();
}

這裏經過類反射的方式來加載要啓動的Activity實例對象。

LoadedApk構造過程

首先介紹一下LoadedApk對象的構造過程:

frameworks\base\core\java\android\app\ ActivityThread.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public final LoadedApk getPackageInfo(String packageName, CompatibilityInfo compatInfo,
         int flags) {
     synchronized (mPackages) {
         //經過Activity的包名從對應的成員變量中查找LoadedApk對象
         WeakReference<loadedapk> ref;
         if ((flags&Context.CONTEXT_INCLUDE_CODE) != 0 ) {
             ref = mPackages.get(packageName);
         } else {
             ref = mResourcePackages.get(packageName);
         }
         LoadedApk packageInfo = ref != null ? ref.get() : null ;
         if (packageInfo != null && (packageInfo.mResources == null
                 || packageInfo.mResources.getAssets().isUpToDate())) {
             ...
             return packageInfo;
         }
     }
     //若是沒有,則爲當前Activity建立對應的LoadedApk對象
     ApplicationInfo ai = null ;
     try {
         //經過包名在PMS服務中查找應用程序信息
         ai = getPackageManager().getApplicationInfo(packageName,
                 PackageManager.GET_SHARED_LIBRARY_FILES, UserId.myUserId());
     } catch (RemoteException e) {
         // Ignore
     }
     //使用另外一個重載函數建立LoadedApk對象
     if (ai != null ) {
         return getPackageInfo(ai, compatInfo, flags);
     }
     return null ;
}
</loadedapk>


?
1
2
3
4
5
6
7
8
9
10
11
12
13
public final LoadedApk getPackageInfo(ApplicationInfo ai, CompatibilityInfo compatInfo,
         int flags) {
     boolean includeCode = (flags&Context.CONTEXT_INCLUDE_CODE) != 0 ;
     boolean securityViolation = includeCode && ai.uid != 0
             && ai.uid != Process.SYSTEM_UID && (mBoundApplication != null
                     ? !UserId.isSameApp(ai.uid, mBoundApplication.appInfo.uid)
                     : true );
     if ((flags&(Context.CONTEXT_INCLUDE_CODE|Context.CONTEXT_IGNORE_SECURITY))
             == Context.CONTEXT_INCLUDE_CODE) {
         ...
     }
     return getPackageInfo(ai, compatInfo, null , securityViolation, includeCode);
}


?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
         ClassLoader baseLoader, boolean securityViolation, boolean includeCode) {
     //再次從對應的成員變量中查找LoadedApk實例
     synchronized (mPackages) {
         WeakReference<loadedapk> ref;
         if (includeCode) {
             ref = mPackages.get(aInfo.packageName);
         } else {
             ref = mResourcePackages.get(aInfo.packageName);
         }
         LoadedApk packageInfo = ref != null ? ref.get() : null ;
         if (packageInfo == null || (packageInfo.mResources != null
                 && !packageInfo.mResources.getAssets().isUpToDate())) {
             ...
             //構造一個LoadedApk對象
             packageInfo = new LoadedApk( this , aInfo, compatInfo, this , baseLoader,
                         securityViolation, includeCode &&
                         (aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0 );
             //保存LoadedApk實例到ActivityThread的相應成員變量中
             if (includeCode) {
                 mPackages.put(aInfo.packageName,
                         new WeakReference<loadedapk>(packageInfo));
             } else {
                 mResourcePackages.put(aInfo.packageName,
                         new WeakReference<loadedapk>(packageInfo));
             }
         }
         return packageInfo;
     }
}
</loadedapk></loadedapk></loadedapk>

frameworks\base\core\java\android\app\LoadedApk.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo,
         CompatibilityInfo compatInfo,
         ActivityThread mainThread, ClassLoader baseLoader,
         boolean securityViolation, boolean includeCode) {
     mActivityThread = activityThread;
     mApplicationInfo = aInfo;
     mPackageName = aInfo.packageName;
     mAppDir = aInfo.sourceDir;
     final int myUid = Process.myUid();
     mResDir = aInfo.uid == myUid ? aInfo.sourceDir
             : aInfo.publicSourceDir;
     if (!UserId.isSameUser(aInfo.uid, myUid) && !Process.isIsolated()) {
         aInfo.dataDir = PackageManager.getDataDirForUser(UserId.getUserId(myUid),
                 mPackageName);
     }
     mSharedLibraries = aInfo.sharedLibraryFiles;
     mDataDir = aInfo.dataDir;
     mDataDirFile = mDataDir != null ? new File(mDataDir) : null ;
     mLibDir = aInfo.nativeLibraryDir;
     mBaseClassLoader = baseLoader;
     mSecurityViolation = securityViolation;
     mIncludeCode = includeCode;
     mCompatibilityInfo.set(compatInfo);
     if (mAppDir == null ) {
         //爲應用程序進程建立一個ContextImpl上下文
         if (ActivityThread.mSystemContext == null ) {
             ActivityThread.mSystemContext =
                 ContextImpl.createSystemContext(mainThread);
             ActivityThread.mSystemContext.getResources().updateConfiguration(
                      mainThread.getConfiguration(),
                      mainThread.getDisplayMetricsLocked(compatInfo, false ),
                      compatInfo);
         }
         mClassLoader = ActivityThread.mSystemContext.getClassLoader();
         mResources = ActivityThread.mSystemContext.getResources();
     }
}

從以上LoadedApk的構造函數能夠看出,LoadedApk類記錄了Activity運行所在的ActivityThread、Activity所在的應用程序信息、Activity的包名、Activity的資源路徑、Activity的庫路徑、Activity的數據存儲路徑、類加載器和應用程序所使用的資源等信息。

Application構造過程

當Activity爲應用程序進程啓動的第一個Activity,所以須要構造一個Application對象

frameworks\base\core\java\android\app\LoadedApk.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public Application makeApplication( boolean forceDefaultAppClass,
         Instrumentation instrumentation) {
     //在應用程序進程空間以單例模式建立Application對象
     if (mApplication != null ) {
         return mApplication;
     }
     Application app = null ;
     //獲得應用程序的Application類名
     String appClass = mApplicationInfo.className;
     //若是應用程序沒用重寫Application,則使用Android默認的Application類
     if (forceDefaultAppClass || (appClass == null )) {
         appClass = "android.app.Application" ;
     }
     try {
         java.lang.ClassLoader cl = getClassLoader();
         //爲Application實例建立一個上下文對象ContextImpl
         ①ContextImpl appContext = new ContextImpl();
         //初始化上下文
         ②appContext.init( this , null , mActivityThread);
         //建立Application實例對象
         ③app = mActivityThread.mInstrumentation.newApplication(
                 cl, appClass, appContext);
         appContext.setOuterContext(app);
     } catch (Exception e) {
         ...
     }
     mActivityThread.mAllApplications.add(app);
     mApplication = app;
     if (instrumentation != null ) {
         try {
             //調用Application的OnCreate函數
             ④instrumentation.callApplicationOnCreate(app);
         } catch (Exception e) {
             ...
         }
     }
     return app;
}

在應用程序開發過程當中,當咱們重寫了Application類後,應用程序加載運行的是咱們定義的Application類,不然就加載運行默認的Application類。從Application對象的構造過程就能夠解釋爲何應用程序啓動後首先執行的是Application的OnCreate函數。在實例化Application對象時,一樣建立並初始化了一個ContextImpl上下文對象。

ContextImpl構造過程

前面咱們介紹了,每個Activity擁有一個上下文對象ContextImpl,每個Application對象也擁有一個ContextImpl上下文對象,那麼ContextImpl對象又是如何構造的呢?

frameworks\base\core\java\android\app\ ContextImpl.java

?
1
2
3
ContextImpl() {
     mOuterContext = this ;
}

ContextImpl的構造過程什麼也沒幹,經過調用ContextImpl的init函數進行初始化

?
1
2
3
final void init(LoadedApk packageInfo,IBinder activityToken, ActivityThread mainThread) {
     init(packageInfo, activityToken, mainThread, null , null );
}

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
final void init(LoadedApk packageInfo,IBinder activityToken, ActivityThread mainThread,
             Resources container, String basePackageName) {
     mPackageInfo = packageInfo;
相關文章
相關標籤/搜索