Activity 中mParent 成员变量是如何被赋值的

来源:互联网 发布:云联惠平台下载软件 编辑:程序博客网 时间:2024/05/21 17:54

在查看Activity源码时,会发现有一个成员变量mParent,很多操作如startActivity中都会先去判断mParent,如果不为空,将会走入另外的分支,那么mParent的作用是什么,又是如何被赋值的呢,今天先来分析下mParent的赋值流程。
mParent 顾名思义,表示是当前Activity的父Activity,那么在什么样的场景下会存在一个Activity中包含Activity的情况呢,很容易就想到是TabActivity,虽然现在已经被Fragment替代,但是不妨碍我们拿它的源码来进行分析。
首先打开TabActivity,其继承自ActivityGroup,包含一个成员变量TabHost

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1.  */  
  2. @Deprecated  
  3. public class TabActivity extends ActivityGroup {  
  4.     private TabHost mTabHost;  
  5.     private String mDefaultTab = null;  
  6.     private int mDefaultTabIndex = -1;  
  7.   
  8.     public TabActivity() {  
  9.     }  

TabActivity对子界面的各种操作都是通过TabHost来完成,打开TabHost的源码

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public class TabHost extends FrameLayout implements ViewTreeObserver.OnTouchModeChangeListener {  
  2.   
  3.     private static final int TABWIDGET_LOCATION_LEFT = 0;  
  4.     private static final int TABWIDGET_LOCATION_TOP = 1;  
  5.     private static final int TABWIDGET_LOCATION_RIGHT = 2;  
  6.     private static final int TABWIDGET_LOCATION_BOTTOM = 3;  
  7.     private TabWidget mTabWidget;  
  8.     private FrameLayout mTabContent;  
  9.     private List<TabSpec> mTabSpecs = new ArrayList<TabSpec>(2);  
  10.     /** 
  11.      * This field should be made private, so it is hidden from the SDK. 
  12.      * {@hide} 
  13.      */  
  14.     protected int mCurrentTab = -1;  
  15.     private View mCurrentView = null;  
  16.     /** 
  17.      * This field should be made private, so it is hidden from the SDK. 
  18.      * {@hide} 
  19.      */  
  20.     protected LocalActivityManager mLocalActivityManager = null;  
  21.     private OnTabChangeListener mOnTabChangeListener;  
  22.     private OnKeyListener mTabKeyListener;  

TabHost 包含了一个TabSpec数组和LocalActivityManager对象 ,这个对象是在TabActivity中初始化

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. @Override  
  2.     public void onContentChanged() {  
  3.         super.onContentChanged();  
  4.         mTabHost = (TabHost) findViewById(com.android.internal.R.id.tabhost);  
  5.   
  6.         if (mTabHost == null) {  
  7.             throw new RuntimeException(  
  8.                     "Your content must have a TabHost whose id attribute is " +  
  9.                     "'android.R.id.tabhost'");  
  10.         }  
  11.         mTabHost.setup(getLocalActivityManager());  
  12.     }  

我们通过TabHost的addTab来添加界面

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public void addTab(TabSpec tabSpec) {  
  2.   
  3.         if (tabSpec.mIndicatorStrategy == null) {  
  4.             throw new IllegalArgumentException("you must specify a way to create the tab indicator.");  
  5.         }  
  6.   
  7.         if (tabSpec.mContentStrategy == null) {  
  8.             throw new IllegalArgumentException("you must specify a way to create the tab content");  
  9.         }  
  10.         View tabIndicator = tabSpec.mIndicatorStrategy.createIndicatorView();  
  11.         tabIndicator.setOnKeyListener(mTabKeyListener);  
  12.   
  13.         // If this is a custom view, then do not draw the bottom strips for  
  14.         // the tab indicators.  
  15.         if (tabSpec.mIndicatorStrategy instanceof ViewIndicatorStrategy) {  
  16.             mTabWidget.setStripEnabled(false);  
  17.         }  
  18.   
  19.         mTabWidget.addView(tabIndicator);  
  20.         mTabSpecs.add(tabSpec);  
  21.   
  22.         if (mCurrentTab == -1) {  
  23.             setCurrentTab(0);  
  24.         }  
  25.     }  

调用setCurrentTab将第一个添加进去的默认显示出来

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public void setCurrentTab(int index) {  
  2.         if (index < 0 || index >= mTabSpecs.size()) {  
  3.             return;  
  4.         }  
  5.   
  6.         if (index == mCurrentTab) {  
  7.             return;  
  8.         }  
  9.   
  10.         // notify old tab content  
  11.         if (mCurrentTab != -1) {  
  12.             mTabSpecs.get(mCurrentTab).mContentStrategy.tabClosed();  
  13.         }  
  14.   
  15.         mCurrentTab = index;  
  16.         final TabHost.TabSpec spec = mTabSpecs.get(index);  
  17.   
  18.         // Call the tab widget's focusCurrentTab(), instead of just  
  19.         // selecting the tab.  
  20.         mTabWidget.focusCurrentTab(mCurrentTab);  
  21.   
  22.         // tab content  
  23.         mCurrentView = spec.mContentStrategy.getContentView();  
  24.   
  25.         if (mCurrentView.getParent() == null) {  
  26.             mTabContent  
  27.                     .addView(  
  28.                             mCurrentView,  
  29.                             new ViewGroup.LayoutParams(  
  30.                                     ViewGroup.LayoutParams.MATCH_PARENT,  
  31.                                     ViewGroup.LayoutParams.MATCH_PARENT));  
  32.         }  
  33.   
  34.         if (!mTabWidget.hasFocus()) {  
  35.             // if the tab widget didn't take focus (likely because we're in touch mode)  
  36.             // give the current tab content view a shot  
  37.             mCurrentView.requestFocus();  
  38.         }  
  39.   
  40.         //mTabContent.requestFocus(View.FOCUS_FORWARD);  
  41.         invokeOnTabChangeListener();  
  42.     }  

可以看到tab content即当前显示的View 是通过TabSpec.ContentStrategy.getContentView来获取的,那么TabSpec.ContentStrategy是如何初始化的呢
TabSpec给我们提供了三个方法来设置

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public TabSpec setContent(int viewId) {  
  2.             mContentStrategy = new ViewIdContentStrategy(viewId);  
  3.             return this;  
  4.         }  
  5.   
  6.         /** 
  7.          * Specify a {@link android.widget.TabHost.TabContentFactory} to use to 
  8.          * create the content of the tab. 
  9.          */  
  10.         public TabSpec setContent(TabContentFactory contentFactory) {  
  11.             mContentStrategy = new FactoryContentStrategy(mTag, contentFactory);  
  12.             return this;  
  13.         }  
  14.   
  15.         /** 
  16.          * Specify an intent to use to launch an activity as the tab content. 
  17.          */  
  18.         public TabSpec setContent(Intent intent) {  
  19.             mContentStrategy = new IntentContentStrategy(mTag, intent);  
  20.             return this;  
  21.         }  

我们一般是通过intent 来设置,所以接下来看下IntentContentStrategy类

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. private class IntentContentStrategy implements ContentStrategy {  
  2.   
  3.         private final String mTag;  
  4.         private final Intent mIntent;  
  5.   
  6.         private View mLaunchedView;  
  7.   
  8.         private IntentContentStrategy(String tag, Intent intent) {  
  9.             mTag = tag;  
  10.             mIntent = intent;  
  11.         }  
  12.   
  13.         public View getContentView() {  
  14.             if (mLocalActivityManager == null) {  
  15.                 throw new IllegalStateException("Did you forget to call 'public void setup(LocalActivityManager activityGroup)'?");  
  16.             }  
  17.             final Window w = mLocalActivityManager.startActivity(  
  18.                     mTag, mIntent);  
  19.             final View wd = w != null ? w.getDecorView() : null;  
  20.             if (mLaunchedView != wd && mLaunchedView != null) {  
  21.                 if (mLaunchedView.getParent() != null) {  
  22.                     mTabContent.removeView(mLaunchedView);  
  23.                 }  
  24.             }  
  25.             mLaunchedView = wd;  
  26.   
  27.             // XXX Set FOCUS_AFTER_DESCENDANTS on embedded activities for now so they can get  
  28.             // focus if none of their children have it. They need focus to be able to  
  29.             // display menu items.  
  30.             //  
  31.             // Replace this with something better when Bug 628886 is fixed...  
  32.             //  
  33.             if (mLaunchedView != null) {  
  34.                 mLaunchedView.setVisibility(View.VISIBLE);  
  35.                 mLaunchedView.setFocusableInTouchMode(true);  
  36.                 ((ViewGroup) mLaunchedView).setDescendantFocusability(  
  37.                         FOCUS_AFTER_DESCENDANTS);  
  38.             }  
  39.             return mLaunchedView;  
  40.         }  
  41.   
  42.         public void tabClosed() {  
  43.             if (mLaunchedView != null) {  
  44.                 mLaunchedView.setVisibility(View.GONE);  
  45.             }  
  46.         }  
  47.     }  

代码中可以看出,当前显示的View 是通过LocalActivityManager.startActivity 获取到Window对象后,获取到Window对象的DecorView
那么怎么得到这个Window对象呢,我们继续查看LocalActivityManager.startActivity 源码

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public Window startActivity(String id, Intent intent) {  
  2.         if (mCurState == INITIALIZING) {  
  3.             throw new IllegalStateException(  
  4.                     "Activities can't be added until the containing group has been created.");  
  5.         }  
  6.           
  7.         boolean adding = false;  
  8.         boolean sameIntent = false;  
  9.   
  10.         ActivityInfo aInfo = null;  
  11.           
  12.         // Already have information about the new activity id?  
  13.         LocalActivityRecord r = mActivities.get(id);  
  14.         if (r == null) {  
  15.             // Need to create it...  
  16.             r = new LocalActivityRecord(id, intent);  
  17.             adding = true;  
  18.         } else if (r.intent != null) {  
  19.             sameIntent = r.intent.filterEquals(intent);   
  20.             if (sameIntent) {  
  21.                 // We are starting the same activity.  
  22.                 aInfo = r.activityInfo;  
  23.             }  
  24.         }  
  25.         if (aInfo == null) {  
  26.             aInfo = mActivityThread.resolveActivityInfo(intent);  
  27.         }  
  28.           
  29.         // Pause the currently running activity if there is one and only a single  
  30.         // activity is allowed to be running at a time.  
  31.         if (mSingleMode) {  
  32.             LocalActivityRecord old = mResumed;  
  33.       
  34.             // If there was a previous activity, and it is not the current  
  35.             // activity, we need to stop it.  
  36.             if (old != null && old != r && mCurState == RESUMED) {  
  37.                 moveToState(old, STARTED);  
  38.             }  
  39.         }  
  40.   
  41.         if (adding) {  
  42.             // It's a brand new world.  
  43.             mActivities.put(id, r);  
  44.             mActivityArray.add(r);  
  45.         } else if (r.activityInfo != null) {  
  46.             // If the new activity is the same as the current one, then  
  47.             // we may be able to reuse it.  
  48.             if (aInfo == r.activityInfo ||  
  49.                     (aInfo.name.equals(r.activityInfo.name) &&  
  50.                             aInfo.packageName.equals(r.activityInfo.packageName))) {  
  51.                 if (aInfo.launchMode != ActivityInfo.LAUNCH_MULTIPLE ||  
  52.                         (intent.getFlags()&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0) {  
  53.                     // The activity wants onNewIntent() called.  
  54.                     ArrayList<ReferrerIntent> intents = new ArrayList<>(1);  
  55.                     intents.add(new ReferrerIntent(intent, mParent.getPackageName()));  
  56.                     if (localLOGV) Log.v(TAG, r.id + ": new intent");  
  57.                     mActivityThread.performNewIntents(r, intents, false /* andPause */);  
  58.                     r.intent = intent;  
  59.                     moveToState(r, mCurState);  
  60.                     if (mSingleMode) {  
  61.                         mResumed = r;  
  62.                     }  
  63.                     return r.window;  
  64.                 }  
  65.                 if (sameIntent &&  
  66.                         (intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_TOP) == 0) {  
  67.                     // We are showing the same thing, so this activity is  
  68.                     // just resumed and stays as-is.  
  69.                     r.intent = intent;  
  70.                     moveToState(r, mCurState);  
  71.                     if (mSingleMode) {  
  72.                         mResumed = r;  
  73.                     }  
  74.                     return r.window;  
  75.                 }  
  76.             }  
  77.               
  78.             // The new activity is different than the current one, or it  
  79.             // is a multiple launch activity, so we need to destroy what  
  80.             // is currently there.  
  81.             performDestroy(r, true);  
  82.         }  
  83.           
  84.         r.intent = intent;  
  85.         r.curState = INITIALIZING;  
  86.         r.activityInfo = aInfo;  
  87.   
  88.         moveToState(r, mCurState);  
  89.   
  90.         // When in single mode keep track of the current activity  
  91.         if (mSingleMode) {  
  92.             mResumed = r;  
  93.         }  
  94.         return r.window;  
  95.     }  

我们添加是一个新的Activity,所以会新建一个LocalActivityRecord,最终会执行到moveToState,注意这里把r 的curState设置为INITIALIZING

继续看moveToState源码

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. private void moveToState(LocalActivityRecord r, int desiredState) {  
  2.         if (r.curState == RESTORED || r.curState == DESTROYED) {  
  3.             // startActivity() has not yet been called, so nothing to do.  
  4.             return;  
  5.         }  
  6.           
  7.         if (r.curState == INITIALIZING) {  
  8.             // Get the lastNonConfigurationInstance for the activity  
  9.             HashMap<String, Object> lastNonConfigurationInstances =  
  10.                     mParent.getLastNonConfigurationChildInstances();  
  11.             Object instanceObj = null;  
  12.             if (lastNonConfigurationInstances != null) {  
  13.                 instanceObj = lastNonConfigurationInstances.get(r.id);  
  14.             }  
  15.             Activity.NonConfigurationInstances instance = null;  
  16.             if (instanceObj != null) {  
  17.                 instance = new Activity.NonConfigurationInstances();  
  18.                 instance.activity = instanceObj;  
  19.             }  
  20.               
  21.             // We need to have always created the activity.  
  22.             if (localLOGV) Log.v(TAG, r.id + ": starting " + r.intent);  
  23.             if (r.activityInfo == null) {  
  24.                 r.activityInfo = mActivityThread.resolveActivityInfo(r.intent);  
  25.             }  
  26.             r.activity = mActivityThread.startActivityNow(  
  27.                     mParent, r.id, r.intent, r.activityInfo, r, r.instanceState, instance);  
  28.             if (r.activity == null) {  
  29.                 return;  
  30.             }  
  31.             r.window = r.activity.getWindow();  
  32.             r.instanceState = null;  
  33.             r.curState = STARTED;  
  34.               
  35.             if (desiredState == RESUMED) {  
  36.                 if (localLOGV) Log.v(TAG, r.id + ": resuming");  
  37.                 mActivityThread.performResumeActivity(r, true"moveToState-INITIALIZING");  
  38.                 r.curState = RESUMED;  
  39.             }  
  40.               
  41.             // Don't do anything more here.  There is an important case:  
  42.             // if this is being done as part of onCreate() of the group, then  
  43.             // the launching of the activity gets its state a little ahead  
  44.             // of our own (it is now STARTED, while we are only CREATED).  
  45.             // If we just leave things as-is, we'll deal with it as the  
  46.             // group's state catches up.  
  47.             return;  
  48.         }  

当判断 r 的curState为INITIALIZING,会调用到ActivityThread的StartActivityNow,同时返回,注意这里把mParent传进去了,这个mParent就是当前的TabActivity对象,那么这个mParent是什么时候赋值的呢
我们查看LocalActivityManager的构造方法

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public LocalActivityManager(Activity parent, boolean singleMode) {  
  2.         mActivityThread = ActivityThread.currentActivityThread();  
  3.         mParent = parent;  
  4.         mSingleMode = singleMode;  
  5.     }  
在构造方法中进行的赋值

那么LocalActivityManager是什么时候初始化的呢
我们知道TabActivity继承了ActivityGroup,查看ActivityGroup源码

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public ActivityGroup() {  
  2.        this(true);  
  3.    }  
  4.      
  5.    public ActivityGroup(boolean singleActivityMode) {  
  6.        mLocalActivityManager = new LocalActivityManager(this, singleActivityMode);  
  7.    }  

this就是当前TabActivity对象
继续回到ActivityThread的StartActivityNow方法

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public final Activity startActivityNow(Activity parent, String id,  
  2.        Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state,  
  3.        Activity.NonConfigurationInstances lastNonConfigurationInstances) {  
  4.        ActivityClientRecord r = new ActivityClientRecord();  
  5.            r.token = token;  
  6.            r.ident = 0;  
  7.            r.intent = intent;  
  8.            r.state = state;  
  9.            r.parent = parent;  
  10.            r.embeddedID = id;  
  11.            r.activityInfo = activityInfo;  
  12.            r.lastNonConfigurationInstances = lastNonConfigurationInstances;  
  13.        if (localLOGV) {  
  14.            ComponentName compname = intent.getComponent();  
  15.            String name;  
  16.            if (compname != null) {  
  17.                name = compname.toShortString();  
  18.            } else {  
  19.                name = "(Intent " + intent + ").getComponent() returned null";  
  20.            }  
  21.            Slog.v(TAG, "Performing launch: action=" + intent.getAction()  
  22.                    + ", comp=" + name  
  23.                    + ", token=" + token);  
  24.        }  
  25.        return performLaunchActivity(r, null);  
  26.    }  

可以看到源码中将TabActivity对象赋值给了ActivityClientRecord的parent对象,然后继续执行Activity启动流程,启动流程同学们应该很熟悉了,最终会执行到Activity的attach方法

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. final void attach(Context context, ActivityThread aThread,  
  2.             Instrumentation instr, IBinder token, int ident,  
  3.             Application application, Intent intent, ActivityInfo info,  
  4.             CharSequence title, Activity parent, String id,  
  5.             NonConfigurationInstances lastNonConfigurationInstances,  
  6.             Configuration config, String referrer, IVoiceInteractor voiceInteractor,  
  7.             Window window) {  
  8.         attachBaseContext(context);  
  9.   
  10.         mFragments.attachHost(null /*parent*/);  
  11.   
  12.         mWindow = new PhoneWindow(this, window);  
  13.         mWindow.setWindowControllerCallback(this);  
  14.         mWindow.setCallback(this);  
  15.         mWindow.setOnWindowDismissedCallback(this);  
  16.         mWindow.getLayoutInflater().setPrivateFactory(this);  
  17.         if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {  
  18.             mWindow.setSoftInputMode(info.softInputMode);  
  19.         }  
  20.         if (info.uiOptions != 0) {  
  21.             mWindow.setUiOptions(info.uiOptions);  
  22.         }  
  23.         mUiThread = Thread.currentThread();  
  24.   
  25.         mMainThread = aThread;  
  26.         mInstrumentation = instr;  
  27.         mToken = token;  
  28.         mIdent = ident;  
  29.         mApplication = application;  
  30.         mIntent = intent;  
  31.         mReferrer = referrer;  
  32.         mComponent = intent.getComponent();  
  33.         mActivityInfo = info;  
  34.         mTitle = title;  
  35.         mParent = parent;  
  36.         mEmbeddedID = id;  
  37.         mLastNonConfigurationInstances = lastNonConfigurationInstances;  
  38.         if (voiceInteractor != null) {  
  39.             if (lastNonConfigurationInstances != null) {  
  40.                 mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;  
  41.             } else {  
  42.                 mVoiceInteractor = new VoiceInteractor(voiceInteractor, thisthis,  
  43.                         Looper.myLooper());  
  44.             }  
  45.         }  
  46.   
  47.         mWindow.setWindowManager(  
  48.                 (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),  
  49.                 mToken, mComponent.flattenToString(),  
  50.                 (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);  
  51.         if (mParent != null) {  
  52.             mWindow.setContainer(mParent.getWindow());  
  53.         }  
  54.         mWindowManager = mWindow.getWindowManager();  
  55.         mCurrentConfig = config;  
  56.     }  

可以看到最终将ActivityClientRecord的parent对象赋值给了Activity的mParent对象,即将TabActivity对象赋值给了子Activity的mParent成员变量。
正常的Activity启动流程中ActivityClientRecord的parent值一直未空,所以我们在分析正常的启动流程时可以忽略mParent
0 0
原创粉丝点击