Handling different startDestination in android single activity Navigation graph - android

I want to implement a single activity project.
After showing splash i want to navigate to HomeFragment or LoginFragment based on user's login condition. In the MainActivity :
override fun onCreate(savedInstanceState: Bundle?) {
val splashScreen = installSplashScreen()
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (userLoggedIn()) {
navigateToHomeScreen()
} else {
navigateToLoginScreen()
}
}
The question is how should i set the navigation xml? Which one of the fragments should be the startDestionation. What's the best approach for a smooth splash/login( sign-in/sign-up/forget-pass)/ home flow.

Related

android navigation graph configration change

I am trying to follow single activity pattern with android navigation component and my %99 of fragment are portrait but I need to make a new fragment can be portrait or landscape without adding new activity how can I achieve. I could't find any resource. is it possible ? if it is how ?
You can add NavController.OnDestinationChangedListener and set orientation according to the current fragment.
Add this in your activity's onCreate:
val navHostFragment = supportFragmentManager.findFragmentById(R.id.your_nav_host_fragment) as NavHostFragment
navHostFragment.navController..addOnDestinationChangedListener { _, destination, _ ->
if (destination.id == R.id.destination_with_orientation) {
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR
} else {
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
}
}
The following steps could be useful for you:
Don't lock screen orientation from AndroidManifest.xml.
Register a listener inside Activity on the childFragmentManager of the NavHostFragment, that will execute callbacks on fragment lifecycle change
override fun onCreate(savedInstanceState: Bundle?) {
//...
val fragments = supportFragmentManager.fragments
check(fragments.size == 1) {
val baseMessage = "Expected 1 fragment to host the app's navigation. Instead found ${fragments.size}."
if (fragments.size == 0) {
val suggestion = "(Make sure you specify `android:name=\"androidx.navigation.fragment." +
"NavHostFragment\"` or override setUpNavigationGraph)"
"$baseMessage $suggestion"
} else baseMessage
}
with(fragments[0].childFragmentManager) {
registerFragmentLifecycleCallbacks(CustomFragmentLifecycleCallbacks(), false)
}
}
private inner class CustomFragmentLifecycleCallbacks : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentViewCreated(fm: FragmentManager, f: Fragment, v: View, savedInstanceState: Bundle?) {}
override fun onFragmentViewDestroyed(fm: FragmentManager, f: Fragment) {}
}
Follow this guide to lock/unlock screen orientation depending upon which Fragment is visible, from the above callback.
NOTE
Fragment tags or instance type could be used for writing conditional statements inside the lifecycle callbacks, based on app's navigation design.
Don't forget to unregisterFragmentLifecycleCallbacks from Activity.onDestroy()
Cheers 🍻

Navigation component: Retain same fragment after orientation change

as I said in the title, I would like to keep my current fragment after rotating the phone. I could actually make it happen by adding
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
in the Manifest. The problem is that my layout configuration is lost every time.
What am I doing wrong? How can I fix it?
I'm using Jetpack Navigation component. Exist a way to navigateToCurrentFragment()?
Edit: Part of onCreate() from Activity()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityBinding.inflate(layoutInflater)
setContentView(binding.root)
val graphInflater = (supportFragmentManager.findFragmentById(R.id.mNavHost) as NavHostFragment).navController.navInflater
val navGraph = graphInflater.inflate(R.navigation.services_nav_graph)
navGraph.startDestination = R.id.FirstFragment
(supportFragmentManager.findFragmentById(R.id.mNavHost) as NavHostFragment).navController.graph = navGraph
}

Navigating to fragment doesn't Work - Kotlin

I was trying to open some fragment however the app keep crashing
I am wondering if it was possible to fix the issue that I got
class HomePage : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home_page)
val addMed = findViewById<Button>(R.id.addMedButton)
val fragManager: FragmentManager = supportFragmentManager
fragManager.beginTransaction().add(R.id.frameLayout, addMed).commit()
}
}
You have to add a fragment, not a button.
Besides, if the button is found by id, it is already present in the activity.

How to handle the back button DrawerNavigation on android with kotlin

I'm using the DrawerLayout with fragments inside and every fragment navigates to another fragment. I was able to handle the physical back button using :
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val callback = requireActivity().onBackPressedDispatcher.addCallback(this) {
findNavController().navigate(R.id.action_user_validation_to_make_money);
}
}
But every time that I go inside another fragment, the toolbar shows a back button :
I would like to know how can I handle that back button. Thanks!
To navigate using up button, as mentioned in the official docs, override onSupportNavigateUp() in your activity class
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp(drawerLayout)
}

Disable multiple instance of fragment

In my main activity when user clicks button it shows him specific fragment. But if he clicks it again it adds another instance to backstack. And then the user needs to click back many times as click on the button.
class AppActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_app)
SharedPreferenceHelper.init(this)
GRPCClient.init(this)
DataBaseHelper.init(this)
imageViewDot.setOnClickListener {
findNavController(this, R.id.navHostFragmentApp).navigate(R.id.syncFragment)
}
}}
How can I prevent it from happening. What I need to do is if fragment is visible the button will not do anything.
try to flag that you already added this fragment and don't do that again
class AppActivity : AppCompatActivity() {
var navigated: Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_app)
SharedPreferenceHelper.init(this)
GRPCClient.init(this)
DataBaseHelper.init(this)
imageViewDot.setOnClickListener {
if(navigated) return
findNavController(this, R.id.navHostFragmentApp).navigate(R.id.syncFragment)
navigated = true
}
}
override fun onBackPressed() {
super.onBackPressed() // removes from back stack if present in there
navigated = false
}
}
or you can use getBackStackEntry or getCurrentBackStackEntry from NavController instance to check that this Fragment is already on the position

Categories

Resources