本文要探討的話題是Android Fragment 是怎樣和 Activity 聯(lián)系在一起的?也就是說為什么在 Fragment 中調(diào)用 getActivity() 就可以返回對應(yīng) Activity 的實(shí)例。
其實(shí)最初的一個疑問是在 Android Studio 中新建一個包含 Fragment 的工程時,MainActivity 里的默認(rèn)代碼為如下形式,那為什么需要添加 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()
}
}
}
我們知道在旋轉(zhuǎn)屏幕或者修改語言等場景下會導(dǎo)致 Activity 的重建(會得到一個新的 Activity 實(shí)例),那既然 Activity 重建了,F(xiàn)ragment 會重建嗎?Fragment#getActivity() 獲取到的實(shí)例是新的 Activity 實(shí)例還是舊的 Activity 實(shí)例呢?如果是新的實(shí)例那么這個實(shí)例是如何更新到 Fragment 里去的呢?
結(jié)論:
- Fragment 也會重建
- Fragment#getActivity() 獲取到的實(shí)例是新的 Activity 實(shí)例
至于 Activity 的實(shí)例是如何賦值到 Fragment 的,且看下面分析,基于 androidx.fragment:fragment:1.3.6 版本。
習(xí)慣性的反向找答案:
- Fragment#getActivity()
final public FragmentActivity getActivity() {
// mHost 是 FragmentHostCallback 的實(shí)例
return mHost == null ? null : (FragmentActivity) mHost.getActivity();
}
- FragmentStateManager#attach() 中對 Fragment 的 mHost 成員進(jìn)行了賦值,用到了 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 成員進(jìn)行賦值
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 成員進(jìn)行了賦值,接著看哪里調(diào)用了該方法
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() 中調(diào)用了 FragmentManager#attachController() 方法,并且第一個參數(shù)和第二個參數(shù)都傳的是 FragmentController 的 mHost 成員,那是因?yàn)檫@里的 mHost 是 FragmentHostCallback 的實(shí)例且 FragmentHostCallback 繼承了 FragmentContainer,所以既可以當(dāng)成 FragmentHostCallback 來用又可以當(dāng)成 FragmentContainer 來用。接著需要看 FragmentController 的 mHost 成員是在哪兒賦值的。
public void attachHost(@Nullable Fragment parent) {
mHost.mFragmentManager.attachController(
mHost, mHost /*container*/, parent);
}
- FragmentController 構(gòu)造方法中進(jìn)行了賦值,下面需要看哪里調(diào)用了 FragmentController#createController() 方法
public static FragmentController createController(@NonNull FragmentHostCallback<?> callbacks) {
return new FragmentController(checkNotNull(callbacks, "callbacks == null"));
}
private FragmentController(FragmentHostCallback<?> callbacks) {
mHost = callbacks;
}
- FragmentActivity 類中實(shí)例化 mFragments 成員的時候調(diào)用了 FragmentController.createController() 方法,并傳遞了一個 HostCallbacks 的實(shí)例過去。還記得 Fragment#getActivity() 的代碼嗎?里面要返回的就是
FragmentHostCallback 的 mActivity 成員,這里 HostCallbacks 繼承自 FragmentHostCallback,而且是 FragmentActivity 的內(nèi)部類,在 HostCallbacks 的構(gòu)造方法里調(diào)用super(FragmentActivity.this /*fragmentActivity*/);傳遞了 FragmentActivity.this 到父類,而 FragmentHostCallback 的構(gòu)造方法里對將FragmentActivity.this賦值給了mActivity成員,因而 Fragment#getActivity() 返回的就是 FragmentActivity 的實(shí)例,也就是我們的 MainActivity 的實(shí)例(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;
}
...
}
總結(jié)
也就是說,在 FragmentActivity 重建的時候,會重新初始化其成員 mFragments,因而重新生成了一個 HostCallbacks 對象并把新的 FragmentActivity 實(shí)例傳遞給了 Fragment,核心代碼
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
測試1:
代碼測試驗(yàn)證 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) 的日志結(jié)果。
加了 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。也就是說我們?yōu)榱颂幚磉@種情況,是有必要在 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)
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────
最后
- 總的來說,通過層層傳遞,F(xiàn)ragmentActivity 的實(shí)例傳遞給了 HostCallbacks 對象持有,因而 Fragment 可以獲取到 Activity 的實(shí)例
- Activity 和 Fragment 在屏幕旋轉(zhuǎn)時都會自動重建
- Activity#onCreate() 里添加 if (savedInstanceState == null) 判斷是為了防止重建時 Fragment 被重復(fù)添加
- 至于 Activity 和 Fragment 是如何被重建的,預(yù)計得看看 Framework 的代碼