在Android中,提供了一个ActivityGroup类,该类是Activity的容器,可以包含多个嵌套进来的Activity,我们接下来将采用源码分析的方式来了解该类的内部实现。
首先,从SDK中和源码中都可以获知,ActivityGroup类的父类是Activity,也就是说二者具有相同的接口和生命周期,同Activity一样,也有onCreate()、onPause()等函数可供我们重载。
在ActivityGroup的源代码中有成员变量
protected LocalActivityManager mLocalActivityManager;
该成员变量在ActivityGroup的构造函数中创建并初始化,可见,ActivityGroup的功能实现肯定是要委托给这个对象来完成了。为了给用户开放对此对象的访问,ActivityGroup提供了
public final LocalActivityManager getLocalActivityManager() { return mLocalActivityManager; }
通过浏览ActivityGroup的源码可以发现,几乎全部是以通过LocalActivityManager对象来完成的具体动作,比如:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Bundle states = savedInstanceState != null ? (Bundle) savedInstanceState.getBundle(STATES_KEY) : null; mLocalActivityManager.dispatchCreate(states); }
下面,我们就来看一下LocalActivityManager的源码。
在该类中,提供了一个私有类
// Internal token for an Activity being managed by LocalActivityManager. private static class LocalActivityRecord extends Binder { LocalActivityRecord(String _id, Intent _intent) { id = _id; intent = _intent; } final String id; // Unique name of this record. Intent intent; // Which activity to run here. ActivityInfo activityInfo; // Package manager info about activity. Activity activity; // Currently instantiated activity. Window window; // Activity's top-level window. Bundle instanceState; // Last retrieved freeze state. int curState = RESTORED; // Current state the activity is in. }
用于保存Activity的信息,并提供了
/** The activity that is currently resumed. */ private LocalActivityRecord mResumed; /** id -> record of all known activities. */ private final Map<String, LocalActivityRecord> mActivities = new HashMap<String, LocalActivityRecord>(); /** array of all known activities for easy iterating. */ private final ArrayList<LocalActivityRecord> mActivityArray = new ArrayList<LocalActivityRecord>();
采用这样的数据结构用于对所有嵌入的子Activity信息进行保存处理。其中前者用于通过String快速查找,后者用于以数组的方式快速访问,是典型的以空间换时间的的方式。
从下面这段代码我们可以看出,当有一个ActivityGroup被create的时候,就会有对应的Activity信息被保存到数组中。
/** * Restore a state that was previously returned by {@link #saveInstanceState}. This * adds to the activity group information about all activity IDs that had * previously been saved, even if they have not been started yet, so if the * user later navigates to them the correct state will be restored. * * <p>Note: This does <b>not</b> change the current running activity, or * start whatever activity was previously running when the state was saved. * That is up to the client to do, in whatever way it thinks is best. * * @param state a previously saved state; does nothing if this is null * * @see #saveInstanceState */ public void dispatchCreate(Bundle state) { if (state != null) { for (String id : state.keySet()) { try { final Bundle astate = state.getBundle(id); LocalActivityRecord r = mActivities.get(id); if (r != null) { r.instanceState = astate; } else { r = new LocalActivityRecord(id, null); r.instanceState = astate; mActivities.put(id, r); mActivityArray.add(r); } } catch (Exception e) { // Recover from -all- app errors. Log.e(TAG, "Exception thrown when restoring LocalActivityManager state", e); } } } mCurState = CREATED; }
当我们调用LocalActivityManager的startActivity()以产生Window的时候,我们也可以看到
/** * Start a new activity running in the group. Every activity you start * must have a unique string ID associated with it -- this is used to keep * track of the activity, so that if you later call startActivity() again * on it the same activity object will be retained. * * <p>When there had previously been an activity started under this id, * it may either be destroyed and a new one started, or the current * one re-used, based on these conditions, in order:</p> * * <ul> * <li> If the Intent maps to a different activity component than is * currently running, the current activity is finished and a new one * started. * <li> If the current activity uses a non-multiple launch mode (such * as singleTop), or the Intent has the * {@link Intent#FLAG_ACTIVITY_SINGLE_TOP} flag set, then the current * activity will remain running and its * {@link Activity#onNewIntent(Intent) Activity.onNewIntent()} method * called. * <li> If the new Intent is the same (excluding extras) as the previous * one, and the new Intent does not have the * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP} set, then the current activity * will remain running as-is. * <li> Otherwise, the current activity will be finished and a new * one started. * </ul> * * <p>If the given Intent can not be resolved to an available Activity, * this method throws {@link android.content.ActivityNotFoundException}. * * <p>Warning: There is an issue where, if the Intent does not * include an explicit component, we can restore the state for a different * activity class than was previously running when the state was saved (if * the set of available activities changes between those points). * * @param id Unique identifier of the activity to be started * @param intent The Intent describing the activity to be started * * @return Returns the window of the activity. The caller needs to take * care of adding this window to a view hierarchy, and likewise dealing * with removing the old window if the activity has changed. * * @throws android.content.ActivityNotFoundException */ public Window startActivity(String id, Intent intent) { if (mCurState == INITIALIZING) { throw new IllegalStateException( "Activities can't be added until the containing group has been created."); } boolean adding = false; boolean sameIntent = false; ActivityInfo aInfo = null; // Already have information about the new activity id? LocalActivityRecord r = mActivities.get(id); if (r == null) { // Need to create it... r = new LocalActivityRecord(id, intent); adding = true; } else if (r.intent != null) { sameIntent = r.intent.filterEquals(intent); if (sameIntent) { // We are starting the same activity. aInfo = r.activityInfo; } } if (aInfo == null) { aInfo = mActivityThread.resolveActivityInfo(intent); } // Pause the currently running activity if there is one and only a single // activity is allowed to be running at a time. if (mSingleMode) { LocalActivityRecord old = mResumed; // If there was a previous activity, and it is not the current // activity, we need to stop it. if (old != null && old != r && mCurState == RESUMED) { moveToState(old, STARTED); } } if (adding) { // It's a brand new world. mActivities.put(id, r); mActivityArray.add(r); } else if (r.activityInfo != null) { // If the new activity is the same as the current one, then // we may be able to reuse it. if (aInfo == r.activityInfo || (aInfo.name.equals(r.activityInfo.name) && aInfo.packageName.equals(r.activityInfo.packageName))) { if (aInfo.launchMode != ActivityInfo.LAUNCH_MULTIPLE || (intent.getFlags()&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0) { // The activity wants onNewIntent() called. ArrayList<Intent> intents = new ArrayList<Intent>(1); intents.add(intent); if (localLOGV) Log.v(TAG, r.id + ": new intent"); mActivityThread.performNewIntents(r, intents); r.intent = intent; moveToState(r, mCurState); if (mSingleMode) { mResumed = r; } return r.window; } if (sameIntent && (intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_TOP) == 0) { // We are showing the same thing, so this activity is // just resumed and stays as-is. r.intent = intent; moveToState(r, mCurState); if (mSingleMode) { mResumed = r; } return r.window; } } // The new activity is different than the current one, or it // is a multiple launch activity, so we need to destroy what // is currently there. performDestroy(r, true); } r.intent = intent; r.curState = INITIALIZING; r.activityInfo = aInfo; moveToState(r, mCurState); // When in single mode keep track of the current activity if (mSingleMode) { mResumed = r; } return r.window; }
有了这个数组,就可以遍历到ActivityGroup中嵌入的Activitys了,从而可以实现ActivityGroup的功能。
以上的分析结果产生的类图如下:
转载自:
http://blog.csdn.net/caowenbin/article/details/5876019