现在的位置: 首页 > 综合 > 正文

Android学习札记33:对ActivityGroup源代码的一些分析

2018年04月04日 ⁄ 综合 ⁄ 共 6828字 ⁄ 字号 评论关闭

    在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






抱歉!评论已关闭.