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
- */
- @Deprecated
- public class TabActivity extends ActivityGroup {
- private TabHost mTabHost;
- private String mDefaultTab = null;
- private int mDefaultTabIndex = -1;
- public TabActivity() {
- }
TabActivity对子界面的各种操作都是通过TabHost来完成,打开TabHost的源码
[java] view plain copy
- public class TabHost extends FrameLayout implements ViewTreeObserver.OnTouchModeChangeListener {
- private static final int TABWIDGET_LOCATION_LEFT = 0;
- private static final int TABWIDGET_LOCATION_TOP = 1;
- private static final int TABWIDGET_LOCATION_RIGHT = 2;
- private static final int TABWIDGET_LOCATION_BOTTOM = 3;
- private TabWidget mTabWidget;
- private FrameLayout mTabContent;
- private List<TabSpec> mTabSpecs = new ArrayList<TabSpec>(2);
- /**
- * This field should be made private, so it is hidden from the SDK.
- * {@hide}
- */
- protected int mCurrentTab = -1;
- private View mCurrentView = null;
- /**
- * This field should be made private, so it is hidden from the SDK.
- * {@hide}
- */
- protected LocalActivityManager mLocalActivityManager = null;
- private OnTabChangeListener mOnTabChangeListener;
- private OnKeyListener mTabKeyListener;
TabHost 包含了一个TabSpec数组和LocalActivityManager对象 ,这个对象是在TabActivity中初始化
[java] view plain copy
- @Override
- public void onContentChanged() {
- super.onContentChanged();
- mTabHost = (TabHost) findViewById(com.android.internal.R.id.tabhost);
- if (mTabHost == null) {
- throw new RuntimeException(
- "Your content must have a TabHost whose id attribute is " +
- "'android.R.id.tabhost'");
- }
- mTabHost.setup(getLocalActivityManager());
- }
我们通过TabHost的addTab来添加界面
[java] view plain copy
- public void addTab(TabSpec tabSpec) {
- if (tabSpec.mIndicatorStrategy == null) {
- throw new IllegalArgumentException("you must specify a way to create the tab indicator.");
- }
- if (tabSpec.mContentStrategy == null) {
- throw new IllegalArgumentException("you must specify a way to create the tab content");
- }
- View tabIndicator = tabSpec.mIndicatorStrategy.createIndicatorView();
- tabIndicator.setOnKeyListener(mTabKeyListener);
- // If this is a custom view, then do not draw the bottom strips for
- // the tab indicators.
- if (tabSpec.mIndicatorStrategy instanceof ViewIndicatorStrategy) {
- mTabWidget.setStripEnabled(false);
- }
- mTabWidget.addView(tabIndicator);
- mTabSpecs.add(tabSpec);
- if (mCurrentTab == -1) {
- setCurrentTab(0);
- }
- }
调用setCurrentTab将第一个添加进去的默认显示出来
[java] view plain copy
- public void setCurrentTab(int index) {
- if (index < 0 || index >= mTabSpecs.size()) {
- return;
- }
- if (index == mCurrentTab) {
- return;
- }
- // notify old tab content
- if (mCurrentTab != -1) {
- mTabSpecs.get(mCurrentTab).mContentStrategy.tabClosed();
- }
- mCurrentTab = index;
- final TabHost.TabSpec spec = mTabSpecs.get(index);
- // Call the tab widget's focusCurrentTab(), instead of just
- // selecting the tab.
- mTabWidget.focusCurrentTab(mCurrentTab);
- // tab content
- mCurrentView = spec.mContentStrategy.getContentView();
- if (mCurrentView.getParent() == null) {
- mTabContent
- .addView(
- mCurrentView,
- new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
- }
- if (!mTabWidget.hasFocus()) {
- // if the tab widget didn't take focus (likely because we're in touch mode)
- // give the current tab content view a shot
- mCurrentView.requestFocus();
- }
- //mTabContent.requestFocus(View.FOCUS_FORWARD);
- invokeOnTabChangeListener();
- }
可以看到tab content即当前显示的View 是通过TabSpec.ContentStrategy.getContentView来获取的,那么TabSpec.ContentStrategy是如何初始化的呢
TabSpec给我们提供了三个方法来设置
[java] view plain copy
- public TabSpec setContent(int viewId) {
- mContentStrategy = new ViewIdContentStrategy(viewId);
- return this;
- }
- /**
- * Specify a {@link android.widget.TabHost.TabContentFactory} to use to
- * create the content of the tab.
- */
- public TabSpec setContent(TabContentFactory contentFactory) {
- mContentStrategy = new FactoryContentStrategy(mTag, contentFactory);
- return this;
- }
- /**
- * Specify an intent to use to launch an activity as the tab content.
- */
- public TabSpec setContent(Intent intent) {
- mContentStrategy = new IntentContentStrategy(mTag, intent);
- return this;
- }
我们一般是通过intent 来设置,所以接下来看下IntentContentStrategy类
[java] view plain copy
- private class IntentContentStrategy implements ContentStrategy {
- private final String mTag;
- private final Intent mIntent;
- private View mLaunchedView;
- private IntentContentStrategy(String tag, Intent intent) {
- mTag = tag;
- mIntent = intent;
- }
- public View getContentView() {
- if (mLocalActivityManager == null) {
- throw new IllegalStateException("Did you forget to call 'public void setup(LocalActivityManager activityGroup)'?");
- }
- final Window w = mLocalActivityManager.startActivity(
- mTag, mIntent);
- final View wd = w != null ? w.getDecorView() : null;
- if (mLaunchedView != wd && mLaunchedView != null) {
- if (mLaunchedView.getParent() != null) {
- mTabContent.removeView(mLaunchedView);
- }
- }
- mLaunchedView = wd;
- // XXX Set FOCUS_AFTER_DESCENDANTS on embedded activities for now so they can get
- // focus if none of their children have it. They need focus to be able to
- // display menu items.
- //
- // Replace this with something better when Bug 628886 is fixed...
- //
- if (mLaunchedView != null) {
- mLaunchedView.setVisibility(View.VISIBLE);
- mLaunchedView.setFocusableInTouchMode(true);
- ((ViewGroup) mLaunchedView).setDescendantFocusability(
- FOCUS_AFTER_DESCENDANTS);
- }
- return mLaunchedView;
- }
- public void tabClosed() {
- if (mLaunchedView != null) {
- mLaunchedView.setVisibility(View.GONE);
- }
- }
- }
代码中可以看出,当前显示的View 是通过LocalActivityManager.startActivity 获取到Window对象后,获取到Window对象的DecorView
那么怎么得到这个Window对象呢,我们继续查看LocalActivityManager.startActivity 源码
[java] view plain copy
- 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<ReferrerIntent> intents = new ArrayList<>(1);
- intents.add(new ReferrerIntent(intent, mParent.getPackageName()));
- if (localLOGV) Log.v(TAG, r.id + ": new intent");
- mActivityThread.performNewIntents(r, intents, false /* andPause */);
- 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;
- }
我们添加是一个新的Activity,所以会新建一个LocalActivityRecord,最终会执行到moveToState,注意这里把r 的curState设置为INITIALIZING
继续看moveToState源码
[java] view plain copy
- private void moveToState(LocalActivityRecord r, int desiredState) {
- if (r.curState == RESTORED || r.curState == DESTROYED) {
- // startActivity() has not yet been called, so nothing to do.
- return;
- }
- if (r.curState == INITIALIZING) {
- // Get the lastNonConfigurationInstance for the activity
- HashMap<String, Object> lastNonConfigurationInstances =
- mParent.getLastNonConfigurationChildInstances();
- Object instanceObj = null;
- if (lastNonConfigurationInstances != null) {
- instanceObj = lastNonConfigurationInstances.get(r.id);
- }
- Activity.NonConfigurationInstances instance = null;
- if (instanceObj != null) {
- instance = new Activity.NonConfigurationInstances();
- instance.activity = instanceObj;
- }
- // We need to have always created the activity.
- if (localLOGV) Log.v(TAG, r.id + ": starting " + r.intent);
- if (r.activityInfo == null) {
- r.activityInfo = mActivityThread.resolveActivityInfo(r.intent);
- }
- r.activity = mActivityThread.startActivityNow(
- mParent, r.id, r.intent, r.activityInfo, r, r.instanceState, instance);
- if (r.activity == null) {
- return;
- }
- r.window = r.activity.getWindow();
- r.instanceState = null;
- r.curState = STARTED;
- if (desiredState == RESUMED) {
- if (localLOGV) Log.v(TAG, r.id + ": resuming");
- mActivityThread.performResumeActivity(r, true, "moveToState-INITIALIZING");
- r.curState = RESUMED;
- }
- // Don't do anything more here. There is an important case:
- // if this is being done as part of onCreate() of the group, then
- // the launching of the activity gets its state a little ahead
- // of our own (it is now STARTED, while we are only CREATED).
- // If we just leave things as-is, we'll deal with it as the
- // group's state catches up.
- return;
- }
当判断 r 的curState为INITIALIZING,会调用到ActivityThread的StartActivityNow,同时返回,注意这里把mParent传进去了,这个mParent就是当前的TabActivity对象,那么这个mParent是什么时候赋值的呢
我们查看LocalActivityManager的构造方法
[java] view plain copy
- public LocalActivityManager(Activity parent, boolean singleMode) {
- mActivityThread = ActivityThread.currentActivityThread();
- mParent = parent;
- mSingleMode = singleMode;
- }
那么LocalActivityManager是什么时候初始化的呢
我们知道TabActivity继承了ActivityGroup,查看ActivityGroup源码
[java] view plain copy
- public ActivityGroup() {
- this(true);
- }
- public ActivityGroup(boolean singleActivityMode) {
- mLocalActivityManager = new LocalActivityManager(this, singleActivityMode);
- }
this就是当前TabActivity对象
继续回到ActivityThread的StartActivityNow方法
[java] view plain copy
- public final Activity startActivityNow(Activity parent, String id,
- Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state,
- Activity.NonConfigurationInstances lastNonConfigurationInstances) {
- ActivityClientRecord r = new ActivityClientRecord();
- r.token = token;
- r.ident = 0;
- r.intent = intent;
- r.state = state;
- r.parent = parent;
- r.embeddedID = id;
- r.activityInfo = activityInfo;
- r.lastNonConfigurationInstances = lastNonConfigurationInstances;
- if (localLOGV) {
- ComponentName compname = intent.getComponent();
- String name;
- if (compname != null) {
- name = compname.toShortString();
- } else {
- name = "(Intent " + intent + ").getComponent() returned null";
- }
- Slog.v(TAG, "Performing launch: action=" + intent.getAction()
- + ", comp=" + name
- + ", token=" + token);
- }
- return performLaunchActivity(r, null);
- }
可以看到源码中将TabActivity对象赋值给了ActivityClientRecord的parent对象,然后继续执行Activity启动流程,启动流程同学们应该很熟悉了,最终会执行到Activity的attach方法
[java] view plain copy
- final void attach(Context context, ActivityThread aThread,
- Instrumentation instr, IBinder token, int ident,
- Application application, Intent intent, ActivityInfo info,
- CharSequence title, Activity parent, String id,
- NonConfigurationInstances lastNonConfigurationInstances,
- Configuration config, String referrer, IVoiceInteractor voiceInteractor,
- Window window) {
- attachBaseContext(context);
- mFragments.attachHost(null /*parent*/);
- mWindow = new PhoneWindow(this, window);
- mWindow.setWindowControllerCallback(this);
- mWindow.setCallback(this);
- mWindow.setOnWindowDismissedCallback(this);
- mWindow.getLayoutInflater().setPrivateFactory(this);
- if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
- mWindow.setSoftInputMode(info.softInputMode);
- }
- if (info.uiOptions != 0) {
- mWindow.setUiOptions(info.uiOptions);
- }
- mUiThread = Thread.currentThread();
- mMainThread = aThread;
- mInstrumentation = instr;
- mToken = token;
- mIdent = ident;
- mApplication = application;
- mIntent = intent;
- mReferrer = referrer;
- mComponent = intent.getComponent();
- mActivityInfo = info;
- mTitle = title;
- mParent = parent;
- mEmbeddedID = id;
- mLastNonConfigurationInstances = lastNonConfigurationInstances;
- if (voiceInteractor != null) {
- if (lastNonConfigurationInstances != null) {
- mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
- } else {
- mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
- Looper.myLooper());
- }
- }
- mWindow.setWindowManager(
- (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
- mToken, mComponent.flattenToString(),
- (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
- if (mParent != null) {
- mWindow.setContainer(mParent.getWindow());
- }
- mWindowManager = mWindow.getWindowManager();
- mCurrentConfig = config;
- }
可以看到最终将ActivityClientRecord的parent对象赋值给了Activity的mParent对象,即将TabActivity对象赋值给了子Activity的mParent成员变量。
正常的Activity启动流程中ActivityClientRecord的parent值一直未空,所以我们在分析正常的启动流程时可以忽略mParent
0 0
- Activity 中mParent 成员变量是如何被赋值的。
- Activity 中mParent 成员变量是如何被赋值的
- View的mParent变量初始化
- 在java中 变量之间是如何赋值的
- java Thread ,Thread.currentThread().getName() 的含义 & 普通成员变量是何时被赋值的
- C++ 类中const成员变量的赋值
- c++ 类中const成员变量的赋值
- c++ 类中const成员变量的赋值
- c++ 类中const成员变量的赋值
- c++ 类中const成员变量的赋值
- Java中的类,成员变量的值,在声明的时候直接赋值与在构造函数中再赋值,这个是无所谓的,还是有什么规矩?
- java类中声明的立即赋值的成员变量,真的立即赋值了吗?
- c++中const成员变量赋值问题
- php中变量赋值是引用的例子
- 看对象是如何调用类成员变量的
- vc++在成员函数中对成员变量赋值
- 类成员变量的赋值与初始化
- 成员变量的初始化和赋值
- isual c++ 中的stdafx.h头文件的作用
- FTP服务器搭建
- Linux命令之stty
- 如何理解前端中的DOM、BOM
- 【error】intellij idea报错处理
- Activity 中mParent 成员变量是如何被赋值的
- Android调试时华为手机不打印logcat的问题
- C#调用外部程序结束后触发事件
- Tinywebserver-一个简易的web服务器
- PAT-B 1033. 旧键盘打字(20)
- hashCode和hash值
- 快速排序的一种实现方法
- C/C++学习之路之C及C++发展史及标准
- 日历组件demo