Android Fragment生命周期跟Activity生命周期原理分析

一、整体概述

在 Android 开发中,FragmentActivity 是构建用户界面的关键组件。Activity 作为应用的重要交互载体,管理着应用的整体界面和生命周期;而 Fragment 则是轻量级的 Activity,可嵌入到 Activity 中,实现界面的模块化和复用。理解 Fragment 生命周期与 Activity 生命周期的关系,对于开发高质量、可维护的 Android 应用至关重要。本文将从源码层面深入剖析这两者生命周期之间的关联,详细阐述它们是如何相互影响和协同工作的。

二、Activity 生命周期基础回顾

2.1 Activity 生命周期方法概述

Activity 的生命周期包含多个重要方法,这些方法在不同阶段被系统调用,开发者可重写这些方法实现特定逻辑。主要方法如下:

  • onCreate(Bundle savedInstanceState)Activity 首次创建时调用,用于初始化布局、数据等。
  • onStart()Activity 即将可见时调用。
  • onResume()Activity 获得焦点并开始与用户交互时调用。
  • onPause()Activity 失去焦点但仍可见时调用,常用于保存数据、释放资源。
  • onStop()Activity 不再可见时调用。
  • onDestroy()Activity 即将销毁时调用,用于释放所有资源。
  • onRestart()Activity 从停止状态重新启动时调用。

2.2 ActivityThread 对 Activity 生命周期的管理

ActivityThread 是 Android 应用的主线程类,负责管理 Activity 的生命周期。以下是启动 Activity 的关键代码:

ini 复制代码
// ActivityThread.java
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
    // 创建 Activity 实例
    Activity a = performLaunchActivity(r, customIntent);
    if (a != null) {
        r.createdConfig = new Configuration(mConfiguration);
        reportSizeConfigurations(r);
        Bundle oldState = r.state;
        // 调用 Activity 的 onResume 方法
        handleResumeActivity(r.token, false, r.isForward,
                !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
    }
}

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    // 获取 Activity 的组件信息
    ActivityInfo aInfo = r.activityInfo;
    if (r.packageInfo == null) {
        r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                Context.CONTEXT_INCLUDE_CODE);
    }

    ComponentName component = r.intent.getComponent();
    if (component == null) {
        component = r.intent.resolveActivity(
            mInitialApplication.getPackageManager());
        r.intent.setComponent(component);
    }

    if (r.activityInfo.targetActivity != null) {
        component = new ComponentName(r.activityInfo.packageName,
                r.activityInfo.targetActivity);
    }

    // 创建 Activity 类加载器
    java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
    // 通过反射创建 Activity 实例
    Activity activity = mInstrumentation.newActivity(
            cl, component.getClassName(), r.intent);
    Context appContext = createBaseContextForActivity(r, activity);
    activity.attach(appContext, this, getInstrumentation(), r.token,
            r.ident, app, r.intent, r.activityInfo, title, r.parent,
            r.embeddedID, r.lastNonConfigurationInstances, config,
            r.referrer, r.voiceInteractor, window, r.configCallback,
            r.assistToken);

    if (customIntent != null) {
        activity.mIntent = customIntent;
    }
    r.lastNonConfigurationInstances = null;
    activity.mStartedActivity = false;
    int theme = r.activityInfo.getThemeResource();
    if (theme != 0) {
        activity.setTheme(theme);
    }

    activity.mCalled = false;
    // 调用 Activity 的 onCreate 方法
    if (r.isPersistable()) {
        mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
    } else {
        mInstrumentation.callActivityOnCreate(activity, r.state);
    }
    if (!activity.mCalled) {
        throw new SuperNotCalledException(
            "Activity " + r.intent.getComponent().toShortString() +
            " did not call through to super.onCreate()");
    }
    r.activity = activity;
    r.stopped = true;
    if (!r.activity.mFinished) {
        // 调用 Activity 的 onStart 方法
        activity.performStart();
        r.stopped = false;
    }
    if (!r.activity.mFinished) {
        if (r.isPersistable()) {
            if (r.state != null || r.persistentState != null) {
                // 调用 Activity 的 onRestoreInstanceState 方法
                mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
                        r.persistentState);
            }
        } else if (r.state != null) {
            mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
        }
    }
    if (!r.activity.mFinished) {
        activity.mCalled = false;
        // 调用 Activity 的 onPostCreate 方法
        if (r.isPersistable()) {
            mInstrumentation.callActivityOnPostCreate(activity, r.state,
                    r.persistentState);
        } else {
            mInstrumentation.callActivityOnPostCreate(activity, r.state);
        }
        if (!activity.mCalled) {
            throw new SuperNotCalledException(
                "Activity " + r.intent.getComponent().toShortString() +
                " did not call through to super.onPostCreate()");
        }
    }
    return activity;
}

从上述代码可以看出,ActivityThread 通过一系列方法调用,依次触发 ActivityonCreateonStart 等生命周期方法。

2.3 Instrumentation 对 Activity 生命周期的监控

Instrumentation 类负责监控 Activity 的生命周期方法调用。例如,callActivityOnCreate 方法会调用 ActivityonCreate 方法:

scss 复制代码
// Instrumentation.java
public void callActivityOnCreate(Activity activity, Bundle icicle) {
    prePerformCreate(activity);
    activity.onCreate(icicle);
    postPerformCreate(activity);
}

InstrumentationActivity 生命周期方法调用前后添加了一些预处理和后处理逻辑,确保 Activity 生命周期的正常执行。

三、Fragment 生命周期基础回顾

3.1 Fragment 生命周期方法概述

Fragment 的生命周期与 Activity 有相似之处,也有独特方法。主要方法如下:

  • onAttach(Context context)FragmentActivity 关联时调用。
  • onCreate(Bundle savedInstanceState)Fragment 被创建时调用,用于初始化数据。
  • onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState):创建 Fragment 的视图时调用,返回 View 对象。
  • onViewCreated(View view, Bundle savedInstanceState)Fragment 的视图创建完成后调用,可用于初始化视图组件。
  • onActivityCreated(Bundle savedInstanceState):关联的 ActivityonCreate 方法执行完成后调用。
  • onStart()Fragment 即将可见时调用。
  • onResume()Fragment 获得焦点并开始与用户交互时调用。
  • onPause()Fragment 失去焦点但仍可见时调用。
  • onStop()Fragment 不再可见时调用。
  • onDestroyView()Fragment 的视图被销毁时调用。
  • onDestroy()Fragment 即将被销毁时调用。
  • onDetach()FragmentActivity 解除关联时调用。

3.2 FragmentManager 对 Fragment 生命周期的管理

FragmentManager 负责管理 Fragment 的生命周期。当 Activity 启动时,FragmentManager 会根据 Activity 的生命周期状态来管理 Fragment 的生命周期。以下是 FragmentManager 中处理 Fragment 生命周期的部分代码:

ini 复制代码
// FragmentManager.java
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
        boolean keepActive) {
    if (f.mState <= newState) {
        switch (f.mState) {
            case Fragment.INITIALIZING:
                if (newState > Fragment.INITIALIZING) {
                    f.onAttach(mHost.getContext());
                    if (!f.mRetaining) {
                        f.performCreate(f.mSavedFragmentState);
                    }
                    f.mState = Fragment.CREATED;
                }
                break;
            case Fragment.CREATED:
                if (newState > Fragment.CREATED) {
                    if (f.mFromLayout) {
                        f.mView = f.performCreateView(f.getLayoutInflater(
                                f.mSavedFragmentState), null, f.mSavedFragmentState);
                        if (f.mView != null) {
                            f.mInnerView = f.mView;
                            f.mView.setSaveFromParentEnabled(false);
                            if (f.mHidden) f.mView.setVisibility(View.GONE);
                            f.onViewCreated(f.mView, f.mSavedFragmentState);
                        }
                    }
                    f.mState = Fragment.ACTIVITY_CREATED;
                }
                break;
            case Fragment.ACTIVITY_CREATED:
                if (newState > Fragment.ACTIVITY_CREATED) {
                    if (!f.mFromLayout) {
                        f.mView = f.performCreateView(f.getLayoutInflater(
                                f.mSavedFragmentState), null, f.mSavedFragmentState);
                        if (f.mView != null) {
                            f.mInnerView = f.mView;
                            f.mView.setSaveFromParentEnabled(false);
                            if (f.mHidden) f.mView.setVisibility(View.GONE);
                            f.onViewCreated(f.mView, f.mSavedFragmentState);
                        }
                    }
                    f.mState = Fragment.STARTED;
                }
                break;
            case Fragment.STARTED:
                if (newState > Fragment.STARTED) {
                    f.performResume();
                    f.mState = Fragment.RESUMED;
                }
                break;
        }
    } else if (f.mState > newState) {
        switch (f.mState) {
            case Fragment.RESUMED:
                if (newState < Fragment.RESUMED) {
                    f.performPause();
                    f.mState = Fragment.STARTED;
                }
                break;
            case Fragment.STARTED:
                if (newState < Fragment.STARTED) {
                    f.performStop();
                    f.mState = Fragment.ACTIVITY_CREATED;
                }
                break;
            case Fragment.ACTIVITY_CREATED:
                if (newState < Fragment.ACTIVITY_CREATED) {
                    if (f.mView != null) {
                        f.performDestroyView();
                    }
                    f.mState = Fragment.CREATED;
                }
                break;
            case Fragment.CREATED:
                if (newState < Fragment.CREATED) {
                    if (!f.mRetaining) {
                        f.performDestroy();
                    }
                    f.onDetach();
                    f.mState = Fragment.INITIALIZING;
                }
                break;
        }
    }
    f.mState = newState;
}

FragmentManager 通过 moveToState 方法根据 Fragment 的当前状态和目标状态,调用相应的生命周期方法,确保 Fragment 生命周期的正确流转。

四、Activity 与 Fragment 生命周期关系的打通

4.1 关联建立阶段

4.1.1 Activity 创建时关联 Fragment

Activity 启动时,ActivityonCreate 方法会被调用。在 onCreate 方法中,会涉及到 Fragment 的恢复和创建操作。以下是 ActivityonCreate 方法相关代码:

less 复制代码
// Activity.java
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // ...
    if (savedInstanceState != null) {
        Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
        mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
                ? mLastNonConfigurationInstances.fragments : null);
    }
    mFragments.dispatchCreate();
    // ...
}
  • restoreAllState 方法:用于恢复之前保存的 Fragment 状态。如果 Activity 是因为配置变化(如屏幕旋转)而重新创建,会从 savedInstanceState 中恢复 Fragment 的状态。
  • dispatchCreate 方法:通知 FragmentManager 开始处理 Fragment 的创建过程。FragmentManager 会遍历所有 Fragment,调用其 performCreate 方法。

4.1.2 Fragment 与 Activity 关联

FragmentManagerdispatchCreate 方法中,会调用 FragmentperformCreate 方法:

ini 复制代码
// FragmentManager.java
void dispatchCreate() {
    mStateSaved = false;
    mDestroyed = false;
    for (int i = 0; i < mActive.size(); i++) {
        Fragment f = mActive.valueAt(i);
        if (f != null) {
            if (!f.mIsCreated) {
                f.performCreate(f.mSavedFragmentState);
            }
        }
    }
}

// Fragment.java
void performCreate(Bundle savedInstanceState) {
    mChildFragmentManager.noteStateNotSaved();
    mState = Fragment.CREATED;
    onCreate(savedInstanceState);
    mIsCreated = true;
}

performCreate 方法中,会调用 FragmentonCreate 方法,同时将 Fragment 的状态设置为 CREATED。此时,FragmentActivity 建立了初步关联。

4.2 视图创建阶段

4.2.1 Activity 视图创建时触发 Fragment 视图创建

Activity 的视图创建过程中,FragmentManager 会根据 Fragment 的状态来决定是否创建 Fragment 的视图。当 Fragment 的状态从 CREATED 转变为 ACTIVITY_CREATED 时,会触发视图创建。以下是 FragmentManagermoveToState 方法相关代码:

java 复制代码
// FragmentManager.java
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
        boolean keepActive) {
    if (f.mState <= newState) {
        switch (f.mState) {
            case Fragment.CREATED:
                if (newState > Fragment.CREATED) {
                    if (f.mFromLayout) {
                        f.mView = f.performCreateView(f.getLayoutInflater(
                                f.mSavedFragmentState), null, f.mSavedFragmentState);
                        if (f.mView != null) {
                            f.mInnerView = f.mView;
                            f.mView.setSaveFromParentEnabled(false);
                            if (f.mHidden) f.mView.setVisibility(View.GONE);
                            f.onViewCreated(f.mView, f.mSavedFragmentState);
                        }
                    }
                    f.mState = Fragment.ACTIVITY_CREATED;
                }
                break;
            // ...
        }
    }
    // ...
}
  • performCreateView 方法:调用 FragmentonCreateView 方法,创建 Fragment 的视图。
  • onViewCreated 方法:在视图创建完成后调用,可用于初始化视图组件。

4.2.2 Fragment 视图与 Activity 视图的关联

Fragment 的视图创建完成后,会被添加到 Activity 的视图层次结构中。在 FragmentManager 中,会通过 FragmentContainer 来管理 Fragment 视图的添加和移除。具体的添加逻辑在 FragmentManageraddFragment 方法中实现:

scss 复制代码
// FragmentManager.java
void addFragment(Fragment fragment, boolean moveToStateNow) {
    mAdded.add(fragment);
    if (moveToStateNow) {
        moveToState(fragment, mCurState, 0, 0, false);
    }
}

通过 addFragment 方法,Fragment 的视图被添加到 Activity 的视图层次结构中,实现了视图的关联。

4.3 可见性变化阶段

4.3.1 Activity 可见性变化触发 Fragment 可见性变化

Activity 的可见性发生变化时,会调用 FragmentManager 的相应方法来通知 Fragment。例如,当 ActivityonStart 方法被调用时,会调用 FragmentManagerdispatchStart 方法

scss 复制代码
// Activity.java
protected void onStart() {
    super.onStart();
    mFragments.dispatchStart();
    // ...
}

// FragmentManager.java
void dispatchStart() {
    mStateSaved = false;
    for (int i = 0; i < mActive.size(); i++) {
        Fragment f = mActive.valueAt(i);
        if (f != null) {
            if (f.mState < Fragment.STARTED) {
                moveToState(f, Fragment.STARTED, 0, 0, false);
            }
        }
    }
}

dispatchStart 方法会遍历所有 Fragment,如果 Fragment 的状态小于 STARTED,则调用 moveToState 方法将其状态转变为 STARTED,并调用 FragmentonStart 方法。

4.3.2 Fragment 可见性状态同步

同样,当 ActivityonResumeonPauseonStop 方法被调用时,会分别调用 FragmentManagerdispatchResumedispatchPausedispatchStop 方法,实现 Fragment 可见性状态的同步。以下是 dispatchResume 方法的代码:

scss 复制代码
// Activity.java
protected void onResume() {
    super.onResume();
    mFragments.dispatchResume();
    // ...
}

// FragmentManager.java
void dispatchResume() {
    mStateSaved = false;
    for (int i = 0; i < mActive.size(); i++) {
        Fragment f = mActive.valueAt(i);
        if (f != null) {
            if (f.mState < Fragment.RESUMED) {
                moveToState(f, Fragment.RESUMED, 0, 0, false);
            }
        }
    }
}

通过这种方式,Fragment 的可见性状态与 Activity 的可见性状态保持同步。

4.4 销毁阶段

4.4.1 Activity 销毁时触发 Fragment 销毁

ActivityonDestroy 方法被调用时,会调用 FragmentManagerdispatchDestroy 方法:

scss 复制代码
// Activity.java
protected void onDestroy() {
    super.onDestroy();
    mFragments.dispatchDestroy();
    // ...
}

// FragmentManager.java
void dispatchDestroy() {
    mDestroyed = true;
    for (int i = 0; i < mActive.size(); i++) {
        Fragment f = mActive.valueAt(i);
        if (f != null) {
            if (f.mState > Fragment.INITIALIZING) {
                moveToState(f, Fragment.INITIALIZING, 0, 0, false);
            }
        }
    }
}

dispatchDestroy 方法会遍历所有 Fragment,将其状态转变为 INITIALIZING,并依次调用 FragmentonDestroyViewonDestroyonDetach 方法。

4.4.2 Fragment 资源释放

Fragment 的销毁过程中,会释放其持有的资源。例如,在 onDestroyView 方法中,会销毁 Fragment 的视图:

ini 复制代码
// Fragment.java
void performDestroyView() {
    mChildFragmentManager.noteStateNotSaved();
    mState = Fragment.CREATED;
    onDestroyView();
    mViewLifecycleOwner.destroy();
    mViewLifecycleOwner = null;
    mView = null;
    mInnerView = null;
}

onDestroy 方法中,会销毁 Fragment 的其他资源:

ini 复制代码
// Fragment.java
void performDestroy() {
    mChildFragmentManager.noteStateNotSaved();
    mState = Fragment.INITIALIZING;
    onDestroy();
    mChildFragmentManager.dispatchDestroy();
    mChildFragmentManager = null;
}

onDetach 方法中,会解除 FragmentActivity 的关联:

ini 复制代码
// Fragment.java
void onDetach() {
    mHost = null;
    mParentFragment = null;
    mFragmentManager = null;
    mChildFragmentManager = null;
    mActivity = null;
    mCalled = true;
}

五、不同场景下的生命周期关系

5.1 正常启动和关闭 Activity

当正常启动一个包含 FragmentActivity 时,ActivityFragment 的生命周期方法会按照上述顺序依次调用。具体流程如下:

  1. ActivityonCreate 方法被调用,触发 FragmentonAttachonCreate 方法。
  2. ActivityonStart 方法被调用,触发 FragmentonStart 方法。
  3. ActivityonResume 方法被调用,触发 FragmentonResume 方法。
  4. 当关闭 Activity 时,ActivityonPause 方法被调用,触发 FragmentonPause 方法。
  5. ActivityonStop 方法被调用,触发 FragmentonStop 方法。
  6. ActivityonDestroy 方法被调用,触发 FragmentonDestroyViewonDestroyonDetach 方法。

5.2 屏幕旋转

当屏幕旋转时,Activity 会被销毁并重新创建。在这个过程中,Fragment 的生命周期会受到影响。为了避免 Fragment 被重复创建,可以使用 setRetainInstance(true) 方法。以下是相关源码分析:

arduino 复制代码
// Fragment.java
public void setRetainInstance(boolean retain) {
    mRetainInstance = retain;
    if (retain) {
        mDetached = false;
    }
}

// FragmentManager.java
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
        boolean keepActive) {
    // ...
    if (f.mState > newState) {
        switch (f.mState) {
            case Fragment.CREATED:
                if (newState < Fragment.CREATED) {
                    if (!f.mRetaining) {
                        f.performDestroy();
                    }
                    f.onDetach();
                    f.mState = Fragment.INITIALIZING;
                }
                break;
            // ...
        }
    }
    // ...
}

mRetainInstancetrue 时,FragmentActivity 销毁时不会被销毁,而是会保留其状态,在 Activity 重新创建时直接恢复。

5.3 低内存情况

在低内存情况下,系统可能会销毁一些不常用的 ActivityFragment 以释放内存。当 Activity 被销毁时,会触发 Fragment 的销毁过程。系统会调用 ActivityonSaveInstanceState 方法保存 ActivityFragment 的状态,当 Activity 重新创建时,会从保存的状态中恢复 Fragment。以下是 ActivityonSaveInstanceState 方法相关代码:

less 复制代码
// Activity.java
protected void onSaveInstanceState(@NonNull Bundle outState) {
    outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
    Parcelable p = mFragments.saveAllState();
    if (p != null) {
        outState.putParcelable(FRAGMENTS_TAG, p);
    }
    getApplication().dispatchActivitySaveInstanceState(this, outState);
}

saveAllState 方法会保存 Fragment 的状态,以便在 Activity 重新创建时恢复。

六、总结

通过对 ActivityFragment 生命周期源码的深入分析,我们可以看到它们之间的生命周期关系是紧密相连的。Activity 作为 Fragment 的容器,通过 FragmentManager 管理 Fragment 的生命周期。在 Activity 的不同生命周期阶段,会触发 Fragment 相应的生命周期方法,实现 FragmentActivity 的协同工作。开发者在使用 Fragment 时,需要深入理解这种生命周期关系,确保在合适的时机进行资源的分配和释放,避免内存泄漏和性能问题。同时,对于不同的场景(如屏幕旋转、低内存情况),需要根据 Fragment 的特性进行合理的处理,以提供更好的用户体验。

以上内容从源码层面详细阐述了 ActivityFragment 生命周期的关系,希望能帮助开发者更好地掌握 Android 开发中这两个重要组件的使用。

相关推荐
奔跑吧 android1 小时前
【android bluetooth 协议分析 12】【A2DP详解 1】【车机侧蓝牙音乐免切源介绍】
android·bluetooth·bt·gd·a2dpsink·免切源·aosp14
飞猿_SIR2 小时前
Android Exoplayer多路不同时长音视频混合播放
android·音视频
前端懒猫2 小时前
android实现USB通讯
android
jiet_h3 小时前
Android锁
android
teacher伟大光荣且正确12 小时前
Qt Creator 配置 Android 编译环境
android·开发语言·qt
飞猿_SIR14 小时前
Android Exoplayer 实现多个音视频文件混合播放以及音轨切换
android·音视频
HumoChen9915 小时前
GZip+Base64压缩字符串在ios上解压报错问题解决(安卓、PC模拟器正常)
android·小程序·uniapp·base64·gzip
沙振宇18 小时前
【HarmonyOS】ArkTS开发应用的横竖屏切换
android·华为·harmonyos
橙子1991101620 小时前
Kotlin 中的作用域函数
android·开发语言·kotlin
zimoyin20 小时前
Kotlin 懒初始化值
android·开发语言·kotlin