带有协程的Android MVVM Jetpack导航组件

时间:2020-07-14 22:05:00

标签: android android-jetpack-navigation

我正在尝试实现android jetpack导航组件。 该案例与官方文档中的案例几乎相同:https://developer.android.com/guide/navigation/navigation-conditional

但是我的情况是,如果用户尚未登录,那么登录访问将记录在数据库(房间)中, 然后系统将强制用户登录。 我用https://developer.android.com/guide/navigation/navigation-global-action声明 登录片段的目的地

Navigation

然后依次定义如下

  1. 主页片段是startDestination,
  2. 如果在数据库中未找到用户数据,请显示登录页面
  3. 如果登录成功,则将用户带回家并保存数据登录到数据库。

我使用MVVM体系结构和协程,它们对REST运行请求 使用翻新。

以下是我使用的一些代码:

  1. 导航(xml)

     <navigation xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:app="http://schemas.android.com/apk/res-auto"
         xmlns:tools="http://schemas.android.com/tools"
         android:id="@+id/nav"
         app:startDestination="@id/homeFragment">
    
         <fragment
             android:id="@+id/homeFragment"
             android:name="com.depo.trask.ui.home.HomeFragment"
             android:label="@string/app_name"
             tools:layout="@layout/fragment_home">
    
             <argument android:name="authentication"
                 android:defaultValue="none" />
    
             <action
                 android:id="@+id/action_homeFragment_to_settingsFragment"
                 app:destination="@id/settingsFragment" />
    
         </fragment>
         <fragment
             android:id="@+id/settingsFragment"
             android:name="com.depo.trask.ui.settings.SettingsFragment"
             android:label="@string/settings" />
    
         <fragment
             android:id="@+id/loginFragment"
             android:name="com.depo.trask.ui.login.LoginFragment"
             android:label="fragment_login"
             tools:layout="@layout/fragment_login" />
    
         <action
             android:id="@+id/action_global_loginFragment"
             app:destination="@id/loginFragment"
             app:launchSingleTop="false"
             app:popUpTo="@+id/nav_host_fragment"
             app:popUpToInclusive="true" />
     </navigation>
    
  2. MainActivity

     class MainActivity : AppCompatActivity() {
    
         private lateinit var navController: NavController
         private lateinit var bottomNavigationView: BottomNavigationView
         private lateinit var toolbar: Toolbar
         private val navigationInMainScreen = setOf(
             R.id.loginFragment,
             R.id.homeFragment,
             R.id.containerShippingFragment,
             R.id.locationFragment,
             R.id.historyFragment,
             R.id.aboutFragment
         )
    
         override fun onCreate(savedInstanceState: Bundle?) {
             setTheme(R.style.Theme_MyTheme)
             super.onCreate(savedInstanceState)
             setContentView(R.layout.activity_main)
             setupNavController()
         }
    
         override fun onSupportNavigateUp(): Boolean {
             navController.navigateUp()
             return super.onSupportNavigateUp()
         }
    
         // Nav Controller
         private fun setupNavController() {
    
             navController = findNavController(R.id.nav_host_fragment)
             setupActionBar()
             setupBottomNavigationBar()
    
             navController.addOnDestinationChangedListener { _, destination, _ ->
    
                 // Listening toolbar
                 when(destination.id){
                     R.id.loginFragment, R.id.aboutFragment -> toolbar.visibility = View.GONE
                     else -> toolbar.visibility = View.VISIBLE
                 }
    
                 // Listening bottom navigation bar
                 when (destination.id) {
                     R.id.loginFragment, R.id.settingsFragment -> bottomNavigationView.visibility = View.GONE
                     else -> bottomNavigationView.visibility = View.VISIBLE
                 }
             }
         }
    
         // Top Bar OR App Bar
         private fun setupActionBar() {
             toolbar = findViewById(R.id.toolbar)
             setSupportActionBar(toolbar)
             val appBarConfiguration = AppBarConfiguration(
                 navigationInMainScreen
             )
             setupActionBarWithNavController(navController, appBarConfiguration)
    
         }
    
         // Bottom Navigation Bar
         private fun setupBottomNavigationBar() {
             bottomNavigationView = findViewById(R.id.bottom_navigation_view)
             bottomNavigationView.setupWithNavController(navController)
         }
     }
    
  3. 首页片段

     class HomeFragment : Fragment() {
    
         ?? Should I usede LoginViewModel ?
    
         override fun onCreateView(
             inflater: LayoutInflater,
             container: ViewGroup?,
             savedInstanceState: Bundle?
         ): View? {
             return inflater.inflate(R.layout.fragment_home, container, false)
         }
    
         override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
             super.onViewCreated(view, savedInstanceState)
             observeAuthenticationState()
         }
    
         private fun observeAuthenticationState() {
             val navController = findNavController()
    
             // REDIRECT USER TO LOGIN PAGE ?
             // How To check it
             navController.navigate(R.id.action_global_loginFragment)
         }   
     }
    
  4. 登录片段

     class LoginFragment : Fragment() {
    
         private lateinit var viewModel: LoginViewModel // How can I shared this to home fragment
         private lateinit var binding: FragmentLoginBinding
    
         override fun onCreateView(
             inflater: LayoutInflater,
             container: ViewGroup?,
             savedInstanceState: Bundle?
         ): View? {
    
             // For Retrofit
             val networkConnectionInterceptor = NetworkConnectionInterceptor(requireContext())
             val api = MyApi(networkConnectionInterceptor)
    
             // For Room
             val db = AppDatabase(context = requireActivity().applicationContext)
    
             // For ViewModel
             val repository = UserRepository(api, db)
             val factory = LoginViewModelFactory(repository)
    
             binding = DataBindingUtil.inflate(
                 inflater,
                 R.layout.fragment_login,
                 container,
                 false
             )
    
             viewModel = ViewModelProvider(this, factory).get(LoginViewModel::class.java)
             binding.buttonLogin.setOnClickListener { loginUser() }
             return binding.root
         }
    
         private fun loginUser() {
             val username = binding.editTextUsername.text.toString().trim()
             val password = binding.editTextPassword.text.toString().trim()
    
             binding.progressBar.show()
             lifecycleScope.launch {
                 try {
                     val loginResponse = viewModel.userLogin(username!!, password!!)
    
                     if(loginResponse.user != null){
                         viewModel.saveLoggedInUser(loginResponse.user)
                     }
    
                     binding.progressBar.hide()
                     binding.root.context.toast(loginResponse.message!!)
    
                 } catch (e: ApiException) {
                     binding.progressBar.hide()
                     binding.root.context.toast( e.toString())
                 } catch (e: NoInternetException) {
                     binding.progressBar.hide()
                     binding.root.context.toast( e.toString())
                 }
             }
         }
     }
    

我的问题吗?

  1. 如何强制用户在家庭碎片上正确登录碎片?
  2. 如何在HomeFragment上使用LoginViewModel?

0 个答案:

没有答案