Android导航组件:如何保存片段状态

时间:2019-05-18 03:43:33

标签: android navigation android-architecture-navigation

我使用bottomNavigationView和导航组件。请告诉我在切换到另一个标签并返回到旧标签后如何不破坏片段?例如,我有三个选项卡-A,B,C。我的开始选项卡是A。导航到B后,然后返回A。当我返回到选项卡A时,我不希望重新创建它。怎么了谢谢

6 个答案:

答案 0 :(得分:2)

如果您可以处理销毁片段但想要保存ViewModel的情况,则可以将其范围限定在Navigation Graph中:

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

了解更多here

答案 1 :(得分:1)

根据open issue,导航功能不直接支持多个后向堆栈-即,由于片段不支持多个后向堆栈,因此当您从A或C返回到B时,保存堆栈B的状态。

根据this comment

  

NavigationAdvancedSample现在可在https://github.com/googlesamples/android-architecture-components/tree/master/NavigationAdvancedSample上获得

     

此示例使用多个NavHostFragments(每个底部导航选项卡一个)来解决Fragment API在支持多个反向堆栈方面的当前限制。

     

我们将继续使用Fragment API以支持多个后向堆栈,并在创建后将Navigation API插入其中,这将消除对NavigationExtensions.kt文件之类的需求。我们将继续使用此问题来跟踪该工作。

因此,您可以立即在应用程序中使用NavigationAdvancedSample方法并为问题加注星标,以便在解决基本问题并将直接支持添加到Navigation时获得更新。

答案 2 :(得分:1)

只需使用 2.4.0-alpha01 或更高版本的导航组件

答案 3 :(得分:0)

在活动上声明片段,并在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()

答案 4 :(得分:0)

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
    )
}

您可以对底部导航中的所有片段执行此模式

答案 5 :(得分:-2)

这可以使用片段显示/隐藏逻辑来实现。

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()
}