簡體   English   中英

Android 導航組件:如何保存片段狀態

[英]Android navigation component: how save fragment state

我使用 bottomNavigationView 和導航組件。 請告訴我如何在切換到另一個選項卡並返回舊選項卡后不破壞片段? 例如,我有三個選項卡 - A、B、C。我的開始選項卡是 A。導航到 B 后,然后返回 A。當我返回選項卡 A 時,我不希望它被重新創建。 怎么辦? 謝謝

根據open issue ,Navigation 不直接支持多個返回堆棧 - 即,當您從 A 或 C 返回到 B 時保存堆棧 B 的狀態,因為 Fragment 不支持多個返回堆棧。

根據此評論

NavigationAdvancedSample 現在可在https://github.com/googlesamples/android-architecture-components/tree/master/NavigationAdvancedSample 獲得

此示例使用多個 NavHostFragment,每個底部導航選項卡一個,以解決 Fragment API 在支持多個返回堆棧方面的當前限制。

我們將繼續使用 Fragment API 以支持多個返回堆棧,並在創建后將 Navigation API 插入其中,這將消除對NavigationExtensions.kt文件等任何內容的需要。 我們將繼續使用此問題來跟蹤該工作。

因此,您現在可以在您的應用程序中使用 NavigationAdvancedSample 方法並為問題加星標,以便您在解決基礎問題並向導航添加直接支持時獲得更新。

如果您可以處理銷毀片段,但想要保存 ViewModel,您可以將其范圍限定到導航圖中:

private val viewModel: FavouritesViewModel by 
    navGraphViewModels(R.id.mobile_navigation) {
        viewModelFactory
    }

在這里閱讀更多

編輯

正如@SpiralDev 所指出的,使用 Hilt 簡化了一點:

private val viewModel: MainViewModel by 
    navGraphViewModels(R.id.mobile_navigation) {
         defaultViewModelProviderFactory     
    }

只需使用導航組件版本 2.4.0-alpha01 或更高版本

class BaseViewModel : ViewModel() {

    val bundleFromFragment = MutableLiveData<Bundle>()
}


class HomeViewModel : BaseViewModel () {

   ... HomeViewModel logic
}

內部主頁片段(底部導航選項卡)

private var viewModel: HomeViewModel by viewModels()

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    viewModel.bundleFromFragment.observe(viewLifecycleOwner, Observer {
      
        val message = it.getString("ARGUMENT_MESSAGE", "")
       binding.edtName.text = message
    })
}

override fun onDestroyView() {
    super.onDestroyView()
    viewModel.bundleFromFragment.value = bundleOf(
        "ARGUMENT_MESSAGE" to binding.edtName.text.toString(),
        "SCROLL_POSITION" to binding.scrollable.scrollY
    )
}

您可以對底部導航中的所有片段執行此模式

更新 2021使用版本 2.4.0-alpha05 或更高版本。 不要使用這個答案或其他等。

這可以使用 Fragment 顯示/隱藏邏輯來實現。

private val bottomFragmentMap = hashMapOf<Int, Fragment>()
bottomFragmentMap[0] = FragmentA.newInstance()
bottomFragmentMap[1] = FragmentB.newInstance()
bottomFragmentMap[2] = FragmentC.newInstance()
bottomFragmentMap[3] = FragmentD.newInstance()


private fun loadFragment(fragmentIndex: Int) {
    val fragmentTransaction = childFragmentManager.beginTransaction()

    val bottomFragment = bottomFragmentMap[fragmentIndex]!!

    // first time case. Add to container
    if (!bottomFragment.isAdded) {
        fragmentTransaction.add(R.id.container, bottomFragment)
    }

    // hide remaining fragments
    for ((key, value) in bottomFragmentMap) {
        if (key == fragmentIndex) {
            fragmentTransaction.show(value)
        } else if (value.isVisible) {
            fragmentTransaction.hide(value)
        }
    }
    fragmentTransaction.commit()
}

在活動上聲明片段並在 onCreate 方法上創建片段實例,然后在 updateFragment 方法中傳遞片段實例。 根據需要創建與底部導航偵聽器項 id 對應的盡可能多的片段實例。

Fragment fragmentA;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);

fragmentA = new Fragment();
updateFragment(fragmentA);
}

public void updateFragment(Fragment fragment) {
FragmentTransaction transaction = 
getSupportFragmentManager().beginTransaction();
transaction.add(R.id.layoutFragment, fragment);
transaction.commit();
}

此外,請確保您正在使用 android.support.v4.app.Fragment 並調用 getSupportFragmentManager()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM