问题描述
我正在尝试将 test navigation 添加到 conditional navigation 文档中的示例中。
演示包含 3 个片段:HomeFragment
、ProfileFragment
和 LoginFragment
。在 ProfileFragment
中有一个条件检查用户是否已连接。如果用户未连接,他将被发送到 LoginFragment
。
配置文件片段
@AndroidEntryPoint
class ProfileFragment : Fragment(R.layout.fragment_profile) {
private val mainviewmodel: Mainviewmodel by activityviewmodels()
private val navController by lazy { findNavController() }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val currentBackStackEntry = navController.currentBackStackEntry!!
currentBackStackEntry.savedStateHandle.getLiveData<Boolean>(LoginFragment.LOGIN_SUCCESSFUL)
.observe(currentBackStackEntry,{ success ->
if (!success) {
val startDestination = navController.graph.startDestination
val navOptions = NavOptions.Builder()
.setPopUpTo(startDestination,true)
.build()
navController.navigate(startDestination,null,navOptions)
}
})
}
override fun onViewCreated(view: View,savedInstanceState: Bundle?) {
super.onViewCreated(view,savedInstanceState)
mainviewmodel.user.observe(viewLifecycleOwner,{
if(!it){
navController.navigate(R.id.loginFragment)
}
})
}
}
如文档中所述,在 onCreate()
方法中,我观察存储在 LOGIN_SUCCESSFUL
中的 SavedStateHandle
值,以便在用户未登录时重定向用户。
登录片段
@AndroidEntryPoint
class LoginFragment : Fragment() {
companion object {
const val LOGIN_SUCCESSFUL: String = "LOGIN_SUCCESSFUL"
}
private val viewmodel: Loginviewmodel by viewmodels()
private val navController by lazy { findNavController() }
private lateinit var savedStateHandle: SavedStateHandle
private lateinit var binding: FragmentLoginBinding
override fun onCreateView(
inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?
): View {
binding = DataBindingUtil.inflate(inflater,R.layout.fragment_login,container,false)
binding.viewmodel = viewmodel
binding.lifecycleOwner = this
return binding.root
}
override fun onViewCreated(view: View,savedInstanceState)
savedStateHandle = navController.prevIoUsBackStackEntry!!.savedStateHandle
savedStateHandle.set(LOGIN_SUCCESSFUL,false)
viewmodel.login.observe(viewLifecycleOwner,ResultObserver {
if (it.status == Status.ERROR) {
Snackbar.make(requireView(),it.message ?: "Error",Snackbar.LENGTH_SHORT).show()
} else if (it.status == Status.SUCCESS) {
savedStateHandle.set(LOGIN_SUCCESSFUL,true)
navController.popBackStack()
}
})
}
}
测试
@Test
fun profileFragment_unauthenticated() {
setAuthentication(false)
val navController = TestNavHostController(ApplicationProvider.getApplicationContext())
launchFragmentInHiltContainer<ProfileFragment> {
navController.setviewmodelStore(viewmodelStore())
navController.setGraph(R.navigation.nav_main)
navController.setCurrentDestination(R.id.profileFragment)
Navigation.setViewNavController(requireView(),navController)
}
assertEquals(navController.currentDestination?.id,R.id.loginFragment)
}
因为我使用 Hilt 进行依赖项注入,所以我需要将片段附加到使用 @AndroidEntryPoint
注释的活动:launchFragmentInHiltContainer
在测试期间,我正在创建 TestNavHostController
的实例并将其分配给片段。
问题是我正在访问 navController
方法中的 onCreate
,而 navController
在 RESUMED
状态期间被实例化(请参阅 FragmentScenario)。导致 java.lang.IllegalStateException: Fragment ProfileFragment ... does not have a NavController set
我知道通过向片段的 navController
添加观察者可以更快地使 viewLifecycleOwnerLiveData
可用。然而,这还不够快。
那么,在这种情况下如何实现测试导航?
可能的解决方案
几天后,我一直在寻找一种向我的片段添加测试的方法,我以为我找到了解决方案。这个想法是将 navController
附加到活动。但是,我对结果并不完全满意,这就是我不发布此解决方案作为答案的原因。对于任何感兴趣的人,我将我的解决方案添加到 github repository。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)