I am developing an App with the google recommended SingleActivity pattern. My scenario is: My App starts with the startDestination at HomeFragment. And If the user is not loggedIn I want to start from LoginFragment. My logic is I save loggedIn status in DataStore which is initially false. When My app starts launching. In my MainActivity, I observe that loggedIn status through ViewModel. Then I passed that status to a function. This is my function.
private fun setDestinationForApp(isLoggedIn: Boolean) {
navController.addOnDestinationChangedListener { _, destination, _ ->
if (destination.id == R.id.dest_home) {
if (!isLoggedIn) {
val authNavOptions = NavOptions.Builder()
.setPopUpTo(R.id.dest_home, true)
.build()
navController.navigate(R.id.action_home_to_login, Bundle(), authNavOptions)
}
}
}
}
This is fine enough. But what I faced is : My app starts show HomeFragment default and then if the user is not loggedIn, destinate to LoginFragment.
I want to display corresponding destination fragment according to my loggedIn status from DataStore. Not want to display the default HomeFragment first.
This may be of Activity lifecycle and Navigation Components callback listeners. But I am not smart enough like that. Please help me I am stuck in this. If my question is not clear or cant be solved. Please help me the appropriate way.
This is my whole MainActivity.
@AndroidEntryPoint
class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::inflate) {
private val navHostFragment: NavHostFragment by lazy {
supportFragmentManager.findFragmentById(R.id.container) as NavHostFragment
}
private val navController: NavController by lazy {
navHostFragment.navController
}
private val appBarConfiguration: AppBarConfiguration by lazy {
AppBarConfiguration(navController.graph)
}
private val loadingDialog: LoadingDialog by lazy { LoadingDialog(this) }
private val viewModel: MainViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setupNavigation()
}
override fun observe() {
super.observe()
lifecycleScope.launchWhenCreated {
viewModel.authState.collect {
setDestinationForApp(it)
}
}
}
private fun setupNavigation() {
setSupportActionBar(binding.authToolbar)
setupActionBarWithNavController(navController, appBarConfiguration)
}
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
fun showLoadingDialog(text: String) {
loadingDialog.apply {
setMessage(text)
setCanceledOnTouchOutside(false)
setCancelable(false)
show()
}
}
fun hideLoadingDialog() {
loadingDialog.hide()
}
private fun setDestinationForApp(isLoggedIn: Boolean) {
navController.addOnDestinationChangedListener { _, destination, _ ->
if (destination.id == R.id.dest_home) {
if (!isLoggedIn) {
val authNavOptions = NavOptions.Builder()
.setPopUpTo(R.id.dest_home, true)
.build()
navController.navigate(R.id.action_home_to_login, Bundle(), authNavOptions)
}
}
}
}
}
This is because the navigation component starts with the start graph fragment. And anyway if you want to go back from LoginFragment
. it gets back to HomeFragment
. So in this case you need to check in startup process for loggedIn status and if the user is not loggedIn you can change the starting point of graph programmatically. This way the starting point will be LoginFragment and it will never navigate to HomeFragment
. And after the login process you can revert this logic to set HomeFragment
as starting point of your navigation graph.