Android Fragment 是怎樣和 Activity 聯(lián)系在一起的?

本文要探討的話題是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í)慣性的反向找答案:

  1. Fragment#getActivity()
final public FragmentActivity getActivity() {
    // mHost 是 FragmentHostCallback 的實(shí)例
    return mHost == null ? null : (FragmentActivity) mHost.getActivity();
}
  1. 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);
}
  1. FragmentManager.getHost() 直接返回了 FragmentManager 的 mHost 成員,接著看 FragmentManager 的 mHost 成員是怎么初始化的
FragmentHostCallback<?> getHost() {
    return mHost;
}
  1. 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;
    
    ...
}
  1. 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);
}
  1. 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;
}
  1. 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)
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────


最后

  1. 總的來說,通過層層傳遞,F(xiàn)ragmentActivity 的實(shí)例傳遞給了 HostCallbacks 對象持有,因而 Fragment 可以獲取到 Activity 的實(shí)例
  2. Activity 和 Fragment 在屏幕旋轉(zhuǎn)時都會自動重建
  3. Activity#onCreate() 里添加 if (savedInstanceState == null) 判斷是為了防止重建時 Fragment 被重復(fù)添加
  4. 至于 Activity 和 Fragment 是如何被重建的,預(yù)計得看看 Framework 的代碼
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容