本文要探讨的话题是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 版本。
习惯性的反向找答案:
- Fragment#getActivity()
final public FragmentActivity getActivity() {
// mHost 是 FragmentHostCallback 的实例
return mHost == null ? null : (FragmentActivity) mHost.getActivity();
}
- 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);
}
- FragmentManager.getHost() 直接返回了 FragmentManager 的 mHost 成员,接着看 FragmentManager 的 mHost 成员是怎么初始化的
FragmentHostCallback<?> getHost() {
return mHost;
}
- 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;
...
}
- 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);
}
- FragmentController 构造方法中进行了赋值,下面需要看哪里调用了 FragmentController#createController() 方法
public static FragmentController createController(@NonNull FragmentHostCallback<?> callbacks) {
return new FragmentController(checkNotNull(callbacks, "callbacks == null"));
}
private FragmentController(FragmentHostCallback<?> callbacks) {
mHost = callbacks;
}
- 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)
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────
最后
- 总的来说,通过层层传递,FragmentActivity 的实例传递给了 HostCallbacks 对象持有,因而 Fragment 可以获取到 Activity 的实例
- Activity 和 Fragment 在屏幕旋转时都会自动重建
- Activity#onCreate() 里添加 if (savedInstanceState == null) 判断是为了防止重建时 Fragment 被重复添加
- 至于 Activity 和 Fragment 是如何被重建的,预计得看看 Framework 的代码