Android Fragment 是怎样和 Activity 联系在一起的?

本文要探讨的话题是Android Fragment 是怎样和 Activity 联系在一起的?也就是说为什么在 Fragment 中调用 getActivity() 就可以返回对应 Activity 的实例。

其实最初的一个疑问是在 Android Studio 中新建一个包含 Fragment 的工程时,MainActivity 里的默认代码为如下形式,那为什么需要添加 if (savedInstanceState == null) 这个判断呢?

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main_activity)

        if (savedInstanceState == null) {
            supportFragmentManager.beginTransaction()
                .replace(R.id.container, MainFragment.newInstance())
                .commitNow()
        }
    }
}

我们知道在旋转屏幕或者修改语言等场景下会导致 Activity 的重建(会得到一个新的 Activity 实例),那既然 Activity 重建了,Fragment 会重建吗?Fragment#getActivity() 获取到的实例是新的 Activity 实例还是旧的 Activity 实例呢?如果是新的实例那么这个实例是如何更新到 Fragment 里去的呢?

结论:
  • Fragment 也会重建
  • Fragment#getActivity() 获取到的实例是新的 Activity 实例

至于 Activity 的实例是如何赋值到 Fragment 的,且看下面分析,基于 androidx.fragment:fragment:1.3.6 版本。

习惯性的反向找答案:

  1. Fragment#getActivity()
final public FragmentActivity getActivity() {
    // mHost 是 FragmentHostCallback 的实例
    return mHost == null ? null : (FragmentActivity) mHost.getActivity();
}
  1. FragmentStateManager#attach() 中对 Fragment 的 mHost 成员进行了赋值,用到了 FragmentManager.getHost() 方法
void attach() {
    if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
        Log.d(TAG, "moveto ATTACHED: " + mFragment);
    }
    // If we have a target fragment, ensure it moves to its expected state first
    // so that this fragment can rely on it as an initialized dependency.
    FragmentStateManager targetFragmentStateManager;
    if (mFragment.mTarget != null) {
        targetFragmentStateManager = mFragmentStore.getFragmentStateManager(
                mFragment.mTarget.mWho);
        if (targetFragmentStateManager == null) {
            throw new IllegalStateException("Fragment " + mFragment
                    + " declared target fragment " + mFragment.mTarget
                    + " that does not belong to this FragmentManager!");
        }
        mFragment.mTargetWho = mFragment.mTarget.mWho;
        mFragment.mTarget = null;
    } else if (mFragment.mTargetWho != null) {
        targetFragmentStateManager = mFragmentStore.getFragmentStateManager(
                mFragment.mTargetWho);
        if (targetFragmentStateManager == null) {
            throw new IllegalStateException("Fragment " + mFragment
                    + " declared target fragment " + mFragment.mTargetWho
                    + " that does not belong to this FragmentManager!");
        }
    } else {
        targetFragmentStateManager = null;
    }
    if (targetFragmentStateManager != null) {
        if (FragmentManager.USE_STATE_MANAGER
                || targetFragmentStateManager.getFragment().mState < Fragment.CREATED) {
            targetFragmentStateManager.moveToExpectedState();
        }
    }
    // 这里对 Fragment 的 mHost 成员进行赋值
    mFragment.mHost = mFragment.mFragmentManager.getHost();
    mFragment.mParentFragment = mFragment.mFragmentManager.getParent();
    mDispatcher.dispatchOnFragmentPreAttached(mFragment, false);
    mFragment.performAttach();
    mDispatcher.dispatchOnFragmentAttached(mFragment, false);
}
  1. FragmentManager.getHost() 直接返回了 FragmentManager 的 mHost 成员,接着看 FragmentManager 的 mHost 成员是怎么初始化的
FragmentHostCallback<?> getHost() {
    return mHost;
}
  1. FragmentManager#attachController() 里对 FragmentManager 的 mHost 成员进行了赋值,接着看哪里调用了该方法
void attachController(@NonNull FragmentHostCallback<?> host,
            @NonNull FragmentContainer container, @Nullable final Fragment parent) {
    if (mHost != null) throw new IllegalStateException("Already attached");
    mHost = host;
    mContainer = container;
    mParent = parent;
    
    ...
}
  1. FragmentController#attachHost() 中调用了 FragmentManager#attachController() 方法,并且第一个参数和第二个参数都传的是 FragmentController 的 mHost 成员,那是因为这里的 mHost 是 FragmentHostCallback 的实例且 FragmentHostCallback 继承了 FragmentContainer,所以既可以当成 FragmentHostCallback 来用又可以当成 FragmentContainer 来用。接着需要看 FragmentController 的 mHost 成员是在哪儿赋值的。
public void attachHost(@Nullable Fragment parent) {
    mHost.mFragmentManager.attachController(
            mHost, mHost /*container*/, parent);
}
  1. FragmentController 构造方法中进行了赋值,下面需要看哪里调用了 FragmentController#createController() 方法
public static FragmentController createController(@NonNull FragmentHostCallback<?> callbacks) {
    return new FragmentController(checkNotNull(callbacks, "callbacks == null"));
}

private FragmentController(FragmentHostCallback<?> callbacks) {
    mHost = callbacks;
}
  1. FragmentActivity 类中实例化 mFragments 成员的时候调用了 FragmentController.createController() 方法,并传递了一个 HostCallbacks 的实例过去。还记得 Fragment#getActivity() 的代码吗?里面要返回的就是 FragmentHostCallback 的 mActivity 成员,这里 HostCallbacks 继承自 FragmentHostCallback,而且是 FragmentActivity 的内部类,在 HostCallbacks 的构造方法里调用 super(FragmentActivity.this /*fragmentActivity*/); 传递了 FragmentActivity.this 到父类,而 FragmentHostCallback 的构造方法里对将 FragmentActivity.this 赋值给了 mActivity 成员,因而 Fragment#getActivity() 返回的就是 FragmentActivity 的实例,也就是我们的 MainActivity 的实例(MainActivity 间接继承自己 FragmentActivity)
public class FragmentActivity extends ComponentActivity implements
        ActivityCompat.OnRequestPermissionsResultCallback,
        ActivityCompat.RequestPermissionsRequestCodeValidator {

    static final String FRAGMENTS_TAG = "android:support:fragments";
    final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
    
    ...
    
    class HostCallbacks extends FragmentHostCallback<FragmentActivity> implements
        ViewModelStoreOwner,
        OnBackPressedDispatcherOwner,
        ActivityResultRegistryOwner,
        FragmentOnAttachListener {
        
        public HostCallbacks() {
            super(FragmentActivity.this /*fragmentActivity*/);
        }
        
        ...
    }
}
public abstract class FragmentHostCallback<E> extends FragmentContainer {
    @Nullable private final Activity mActivity;
    @NonNull private final Context mContext;
    @NonNull private final Handler mHandler;
    private final int mWindowAnimations;
    final FragmentManager mFragmentManager = new FragmentManagerImpl();

    public FragmentHostCallback(@NonNull Context context, @NonNull Handler handler,
            int windowAnimations) {
        this(context instanceof Activity ? (Activity) context : null, context, handler,
                windowAnimations);
    }

    @SuppressWarnings("deprecation")
    FragmentHostCallback(@NonNull FragmentActivity activity) {
        this(activity, activity /*context*/, new Handler(), 0 /*windowAnimations*/);
    }

    FragmentHostCallback(@Nullable Activity activity, @NonNull Context context,
            @NonNull Handler handler, int windowAnimations) {
        mActivity = activity;
        mContext = Preconditions.checkNotNull(context, "context == null");
        mHandler = Preconditions.checkNotNull(handler, "handler == null");
        mWindowAnimations = windowAnimations;
    }

    ...
}
总结

也就是说,在 FragmentActivity 重建的时候,会重新初始化其成员 mFragments,因而重新生成了一个 HostCallbacks 对象并把新的 FragmentActivity 实例传递给了 Fragment,核心代码
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());


测试1:

代码测试验证 Activity 和 Fragment 都是重建了的。

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        LogUtils.d("activity: $this")
        setContentView(R.layout.main_activity)

        if (savedInstanceState == null) {
            supportFragmentManager.beginTransaction()
                .replace(R.id.container, MainFragment.newInstance())
                .commitNow()
        }
    }
}

class MainFragment : Fragment() {

    companion object {
        fun newInstance() = MainFragment()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        LogUtils.d("fragment: $this")
    }
}

得到的日志:

2021-09-18 09:56:29.058 24949-24949/com.xxx D/hehe:  
    ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    │ main, com.xxx.MainActivity.onCreate(MainActivity.kt:15)
    ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
    │ activity: com.xxx.MainActivity@4367101
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────
2021-09-18 09:56:29.178 24949-24949/com.xxx D/hehe:  
    ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    │ main, com.xxx.ui.main.MainFragment.onCreate(MainFragment.kt:48)
    ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
    │ fragment: MainFragment{9a4435c} (d2788347-4d76-48c5-b71b-8d39106acc08 id=0x7f080075)
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────

2021-09-18 09:56:36.439 24949-24949/com.xxx D/hehe:  
    ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    │ main, com.xxx.ui.main.MainFragment.onCreate(MainFragment.kt:48)
    ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
    │ fragment: MainFragment{e25e9b2} (d2788347-4d76-48c5-b71b-8d39106acc08 id=0x7f080075)
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────
2021-09-18 09:56:36.442 24949-24949/com.xxx D/hehe:  
    ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    │ main, com.xxx.MainActivity.onCreate(MainActivity.kt:15)
    ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
    │ activity: com.xxx.MainActivity@c1e919b
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────

测试2:

将 replace 换成 add,分别看看加和不加 if (savedInstanceState == null) 的日志结果。

加了 if (savedInstanceState == null) 和上面使用 replace 是类似的情况,再次证明 Activity 和 Fragment 都是可以自动重建的。

2021-09-22 08:40:09.293 29131-29131/com.xxx D/hehe:  
    ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    │ main, com.xxx.MainActivity.onCreate(MainActivity.kt:15)
    ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
    │ activity: com.xxx.MainActivity@4367101
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────
2021-09-22 08:40:09.422 29131-29131/com.xxx D/hehe:  
    ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    │ main, com.xxx.ui.main.MainFragment.onCreate(MainFragment.kt:46)
    ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
    │ fragment: MainFragment{e733e2e} (f4abb74d-3793-4e94-a2fb-e535f253ef71 id=0x7f080075)
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────

2021-09-22 08:40:17.824 29131-29131/com.xxx D/hehe:  
    ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    │ main, com.xxx.ui.main.MainFragment.onCreate(MainFragment.kt:46)
    ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
    │ fragment: MainFragment{276687c} (f4abb74d-3793-4e94-a2fb-e535f253ef71 id=0x7f080075)
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────
2021-09-22 08:40:17.862 29131-29131/com.xxx D/hehe:  
    ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    │ main, com.xxx.MainActivity.onCreate(MainActivity.kt:15)
    ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
    │ activity: com.xxx.MainActivity@18a694d
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────

不加 if (savedInstanceState == null) 的情况,有两个 Fragment 会被添加,一个是自动重建的那个 Fragment,另一个是重建 Activity 时在 Activity#onCreate() 里再次被添加的 Fragment。也就是说我们为了处理这种情况,是有必要在 Activity#onCreate() 方法里添加 if (savedInstanceState == null) 这个判断的!

2021-09-22 08:42:56.021 29207-29207/com.xxx D/hehe:  
    ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    │ main, com.xxx.MainActivity.onCreate(MainActivity.kt:15)
    ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
    │ activity: com.xxx.MainActivity@561e0e4
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────
2021-09-22 08:42:56.119 29207-29207/com.xxx D/hehe:  
    ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    │ main, com.xxx.ui.main.MainFragment.onCreate(MainFragment.kt:46)
    ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
    │ fragment: MainFragment{c04eefe} (167e2397-faea-425e-8197-6f811accddee id=0x7f080075)
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────

2021-09-22 08:43:01.220 29207-29207/com.xxx D/hehe:  
    ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    │ main, com.xxx.ui.main.MainFragment.onCreate(MainFragment.kt:46)
    ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
    │ fragment: MainFragment{ea5a1e9} (167e2397-faea-425e-8197-6f811accddee id=0x7f080075)
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────
2021-09-22 08:43:01.253 29207-29207/com.xxx D/hehe:  
    ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    │ main, com.xxx.MainActivity.onCreate(MainActivity.kt:15)
    ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
    │ activity: com.xxx.MainActivity@f3a5296
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────
2021-09-22 08:43:01.258 29207-29207/com.xxx D/hehe:  
    ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    │ main, com.xxx.ui.main.MainFragment.onCreate(MainFragment.kt:46)
    ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
    │ fragment: MainFragment{99172b8} (acc0f35f-3f2a-4197-93ef-c8b3836f341f id=0x7f080075)
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────


最后

  1. 总的来说,通过层层传递,FragmentActivity 的实例传递给了 HostCallbacks 对象持有,因而 Fragment 可以获取到 Activity 的实例
  2. Activity 和 Fragment 在屏幕旋转时都会自动重建
  3. Activity#onCreate() 里添加 if (savedInstanceState == null) 判断是为了防止重建时 Fragment 被重复添加
  4. 至于 Activity 和 Fragment 是如何被重建的,预计得看看 Framework 的代码
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容