2

I've a navigation graph with 2 fragments, Fragment A and Fragment B. Fragment A is my start destination.

If I'm in Fragment B and I open the app settings, and revoke a permission I see that:

  1. activity is recreated, but I don't see onDestory is called
  2. instead of starting the activity with Fragment A, the activity is started with Fragment B.

I also see that the application is recreated and opens directly Activity B instead of starting from Activity A (old code, we have few activities)

is there a way to reset the navigation graph somehow so it will start from Fragment A?

Thanks.

Sharas
  • 1,985
  • 3
  • 20
  • 43
  • On which condition you're willing to reset the navigation graph? For example: when app permission is revoked then fragment A should be loaded. – Abdullah Javed Jun 23 '22 at 14:25
  • Hi @AbdullahJaved, I would like to reset it in when ever the Activity is created (or recreated) – Sharas Jun 23 '22 at 17:21

3 Answers3

2

Ran into your question looking for an answer for a similar problem.

In my case, I have a single Activity app which is in Fragment B when the permission state is changed, and also reopens in Fragment B after the Activity is restarted. Like you, I want my Activity to start with Fragment A, which is also the start or default destination of my nav graph.

The way I solved my problem was that, I would detect whenever the Activity had been exited because of a REASON_PERMISSION_CHANGE, then I nullify the savedInstanceState inside my Activity's onCreate().

Here's some code:

// MainActivity.kt
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(
            when (requiresPermissionChangeRestart()) {
                true -> {
                    Log.e(TAG "Resetting Activity after permissions manual change")
                    null
                }
                false -> {
                    savedInstanceState
                }
            }
        )
    }
...
    private fun requiresPermissionChangeRestart(): Boolean = (getSystemService(Context.ACTIVITY_SERVICE)
            as ActivityManager).let { am ->
        am.getHistoricalProcessExitReasons(null, 0, 0)
            .find {
                it.reason == ApplicationExitInfo.REASON_PERMISSION_CHANGE
            }
            .run {
                when (this != null) {
                    true -> {
                        Log.w(TAG, "Permissions for package $packageName where changed by the user")
                        true
                    }
                    false -> false
                }
            }
    }

}

It might be kind of a hack, but this little trick might help you arrive at a more fitting solution for your particular problem. As long as you get rid of the savedInstanceState from the given Activity when it matters, you should be able to restart your Activity the way you would expect it to do so.

Ivan Garza
  • 553
  • 2
  • 14
  • If the reason to skip keeping state of the NavHost is the some init stages (which can be missed on deep fragment wake up) - this is not a hack. – A. Petrov Jun 09 '23 at 14:17
1

This code will reset nav graph when the activity will recreate.

override fun onStart() {
    super.onStart()
    navController.setGraph(R.navigation.your_nav_graph)
}
Abdullah Javed
  • 459
  • 3
  • 17
1

I ended up doing it this way: in onCreate:

savedInstanceState?.let {
        if (!ConfigChange) {
            val fragment: Fragment? =
                supportFragmentManager.findFragmentById(R.id.my_nav_host)
            fragment.let {
                if (it is NavHostFragment) {
                    it.navController.navigate(R.id.fragmentA)
                }
            }
        }
    }
Sharas
  • 1,985
  • 3
  • 20
  • 43