Компонент архитектуры навигации - экран входа

Я планирую реализовать навигацию следующим образом:
введите описание изображения здесь
Проблема, с которой я сталкиваюсь, заключается в том, когда пользователь находится в LoginFragmennt и нажимает кнопку назад, он снова загружается LognFragment то есть. застрял в петле.

Я перехожу к LoginnFragment используя условную навигацию согласно этому ответу.

Как правильно это реализовать?

1 ответ

Решение

Одним из решений, которое я могу предложить, является переопределение внутри вашего действия на методе onBackPressed и завершение действия, если ваше текущее назначение (до того, как обработано заднее нажатие) является фрагментом входа.

override fun onBackPressed() {
    val currentDestination=NavHostFragment.findNavController(nav_host_fragment).currentDestination
    when(currentDestination.id) {
        R.id.loginFragment -> {
            finish()
        }
    }
    super.onBackPressed()
}

ИМХО, как я делаю это в моем приложении, немного чище. Просто добавьте эти настройки в график навигации:

<fragment
    android:id="@+id/profile_dest"
    android:name="com.example.ProfileFragment">
    <action
        android:id="@+id/action_profile_dest_to_login_dest"
        app:destination="@id/login_dest"
        app:popUpTo="@+id/profile_dest"
        app:popUpToInclusive="true" />       
</fragment>

а затем перейдите к входу через

findNavController().navigate(R.id.action_profile_dest_to_login_dest),

popUpTo и popUpToInclusive закрыть ProfileFragment когда мы перейдем к LoginFragment так что если пользователь переходит обратно, он выходит из приложения.

Вот официальное решение, предложенное Яном Лейком в видео о навигации по навигации от 23 июля 2020 г. на канале YouTube для разработчиков Android. Решение основано на версии навигации 2.3, в которой появилась возможность возвращать результат в предыдущий пункт назначения.

В нашем случае фрагмент логина возвращает LOGIN_SUCCESSFUL в предыдущий пункт назначения, это может быть фрагмент профиля или любой другой фрагмент, требующий входа в систему.

       class LoginFragment : Fragment(R.layout.login) {
    ...

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        val navController = findNavController()
        val savedStateHandle = navController.previousBackStackEntry?.savedStateHandle
            ?: throw IllegalStateException("the login fragment must not be a start destination")
            
        savedStateHandle.set(LOGIN_SUCCESSFUL, false)
        // Hook up your UI, ask for login
        
        userRepository.addLoginSuccessListener {
            savedStateHandle.set(LOGIN_SUCCESSFUL, true)
            navController.popBackStack()
        } 
    }
}

Фрагмент профиля подписывается на LOGIN_SUCCESSFULсостояние и обрабатывает его. Обратите внимание, что лямбда-выражение наблюдателя не будет вызываться до тех пор, пока фрагмент входа в систему не поместит результат и не вернется обратно к фрагменту профиля.

       class ProfileFragment : Fragment(R.layout.profile) {
    ...
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        val navController = findNavController()
        viewLifecycleOwner.lifecycleScope.launchWhenStarted {
            userRepository.userFlow.collect { user -> 
                if (user == null) {
                    navController.navigate(R.id.login)
                }
            }
        }
        
        val savedStateHandle = navController.currentBackStackEntry?.savedStateHandle
            ?: throw IllegalStateException()
        
        savedStateHandle.getLiveData<Boolean>(LOGIN_SUCCESSFUL)
            .observe(viewLifecycleOwner) { success -> 
                if (!success) {
                    // do whathever we want, just for an example go to
                    // the start destination which doesn't require login
                    val startDestination = navController.graph.startDestination
                    navController.navigate(startDestination, navOptions {
                        popUpTo(startDestination {
                            inclusive = true
                        })
                    })
                }
            }
    }
}
Другие вопросы по тегам