在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.youkuaiyun.com/caowenbin/article/details/5876019
本文详细分析了Android中ActivityGroup类的内部结构和实现方式,通过源码解读,展示了如何利用ActivityGroup作为Activity的容器,管理多个嵌套的Activity。重点介绍了ActivityGroup与LocalActivityManager之间的交互,以及如何通过LocalActivityManager实现Activity的创建、启动和状态管理。此外,还阐述了ActivityGroup中数据结构的设计,以高效地保存和访问嵌入的Activity信息。
1万+

被折叠的 条评论
为什么被折叠?



