So I setup my BottomNavigationView
(like here) using Navigation Component library and everything works fine, every tab can keep their back stacks. However, if I add a Splash screen (Fragment
) and:
popUpInclusive
set to true already)then all the tabs no longer keep their back stacks, plus the navigation becomes weird:
Splash -> Home (first tab) -> Me (second tab) -> Home -> press back, it goes back to Me instead of exiting the app.
PS: I'm using single Activity pattern with single navigation graph.
Ok, thanks to @ianhanniballake, I post my final solution here, the key point is that the BottomNavigationView
must be the start destination insead of other conditional destination like login or splash screen.
Step 1. Create and Setup Splash Layout and Fragment
Add SplashFragment
into Navigation graph.
No need to create action from HomeFragment
-> SplashFragment
, unless you need transition animation
Step 2. Setup MainViewModel
(shared ViewModel
)
class MainViewModel : ViewModel() {
private var _isFirstLaunch = true //replace with the real condition in the future
val isFirstLaunch: Boolean //will be accessed by SplashFragment and HomeFragment
get() = _isFirstLaunch
fun updateIsFirstLaunch(isFirstLaunch: Boolean) {
_isFirstLaunch = isFirstLaunch
}
}
Step 3. Setup HomeFragment
class HomeFragment : Fragment() {
private lateinit var binding: FragmentHomeBinding
private lateinit var mainViewModel: MainViewModel //shared ViewModel
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_home, container, false)
mainViewModel = ViewModelProvider(requireActivity()).get(MainViewModel::class.java)
if (mainViewModel.isFirstLaunch) {
findNavController().navigate(R.id.splashFragment) //no need action, unless you want transition animation
}
binding.goButton.setOnClickListener {
findNavController().navigate(R.id.action_homeFragment_to_home2Fragment)
}
return binding.root
}
}
Step 4. Setup SplashFragment
class SplashFragment : Fragment() {
private lateinit var binding: FragmentSplashBinding
private lateinit var mainViewModel: MainViewModel //shared ViewModel
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_splash, container, false)
mainViewModel = ViewModelProvider(requireActivity()).get(MainViewModel::class.java)
binding.exitSplashButton.setOnClickListener {
mainViewModel.updateIsFirstLaunch(false) //update the condition
findNavController().navigateUp() //go back to HomeFragment
}
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
requireActivity().finish()
}
return binding.root
}
}