Application implementation of Android MVVM architecture

Posted by stubarny on Fri, 31 Dec 2021 03:15:29 +0100

Although the MVVM architecture was also used in previous projects, I was not familiar with the overall MVVM architecture because I did not build the overall framework myself, so I built and implemented the MVVM architecture myself this time.

The components used by MVVM architecture include ViewModel, LiveData, ViewBinding/DataBinding, etc. these components are all components in Jetpack library. Before using ViewModel, you need to establish the concept of four categories:

  • ViewModelProcider.Factory: factory is used to generate ViewModel
  • ViewModel: holds LiveData, obtains data from the Repository, and provides data to the View
  • Repository: obtain and process data, which can be obtained and processed from the network, database or other API s
  • LiveData: observable data storage with life cycle awareness, notifying View to display data

The following figure shows the MVVM architecture diagram and the role of related components in it.

After understanding the basic architecture of MVVM and the role of each component, you can start code implementation. My original intention of doing this project is to collect the commonly used open source libraries for Android recently, so as to display an application more conveniently. This project uses Bmob as background database directly. After accessing Bmob SDK, calling API can get data directly, so as to simulate the background interface. At the same time, this project uses Koin as the framework of dependency injection, eliminating the need to initialize ViewModel, Repository and viewmodelproducer Factory process.

Paste the project directory first, and focus on the highlighted file (the implementation of Factory class is omitted by using Koin):

  1. ViewModel class:

    To implement the HomeViewModel class, you need to inherit from ViewModel() as the ViewModel of the HomeFragment. The construction parameter of the HomeViewModel class is BmobRepository. A LiveData variable in the class is used to carry data. A function getAllRecommendLibrary() obtains open source library data. The function implementation is that the repository obtains data in the cloud database in the process:

    class HomeViewModel(private val repository: BmobRepository) : ViewModel() {
        var libraryRecommendData = MutableLiveData<MutableList<AndroidLibrary>>()
    
        fun getAllRecommendLibrary() {
            viewModelScope.launch {
                repository.getAllRecommendLibrary(libraryRecommendData)
            }
        }
    }
    
  2. Repository class:

    Implement the BmobRepository class as the data provider of HomeViewModel. In the BmobRepository class, there is a pending function getallrecommendlibrary (libraryrerecommenddata: mutablelivedata < mutablelist >) to obtain the data in the cloud database. The parameter of the function is LiveData. After obtaining the data, use setValue to notify the View to display the data.

    class BmobRepository {
        /**
         * Get all recommended open source projects in Bmob
         */
        suspend fun getAllRecommendLibrary(libraryRecommendData: MutableLiveData<MutableList<AndroidLibrary>>) {
            return withContext(Dispatchers.IO) {
                val bombQuery: BmobQuery<AndroidLibrary> = BmobQuery()
                bombQuery.findObjects(object : FindListener<AndroidLibrary>() {
                    override fun done(data: MutableList<AndroidLibrary>?, ex: BmobException?) {
                        if (ex == null) {
                            Timber.d("Bmob find success")
                            libraryRecommendData.value = data!!
                        } else {
                            Timber.d("Bmob exception $ex")
                        }
                    }
                })
            }
        }
    }
    
  3. Koin initialization:

    Koin's initialization is divided into two steps:

    • Define the ViewModel, tell Kioin where to find the ViewModel and Repository and generate them automatically. Here, I choose to write them directly in the BaseApplication. Note that it needs to be defined in the outermost layer, that is, at the same level as the Classt:
    • Initialize Koin in onCreate() function of Application:

      class BaseApplication : Application() {
          override fun onCreate() {
              super.onCreate()
              //Initialize Bmob
              Bmob.initialize(this, Constant.BMOB_APP_ID)
              //Initialize Timber
              if (BuildConfig.DEBUG) {
                  Timber.plant(Timber.DebugTree())
              }
      
              //Step 2:
              startKoin {
                  //Android context
                  androidContext(this@BaseApplication)
                  //modules
                  val list = listOf(myModule, repoModel)
                  modules(list)
              }
          }
      }
      //Step 1:
      //Define a myModule as the Viewmodel
      val myModule = module {
          viewModel { HomeViewModel(get()) }
      }
      //Define a repoModule
      val repoModel = module {
          single { BmobRepository() }
      }
      
  4. Fragment class implementation:

Implement the HomeFragment class as the view layer, which is divided into two steps:

  • The variable homeViewModel is used as the ViewModel to obtain data. The initialization method after using Koin is very simple

    private val homeViewModel: HomeViewModel by viewModel()//Lazy load initialization
    
  • LiveData registration monitors data changes in the ViewModel and implements operations after obtaining data

        private fun initRegister() {
            //After LiveData registers and listens in the view layer, it can continuously receive data when the data in the ViewModel changes
            homeViewModel.libraryRecommendData.observe(viewLifecycleOwner, {
                Timber.d("t $it")
                (binding.rvAndroidLibrary.adapter as AndroidLibraryAdapter).apply {
                    data = it
                    notifyDataSetChanged()
                }
            })
        }
    
  • ViewModel calls the function to notify the Repository to query data:

        override fun onResume() {
            super.onResume()
            homeViewModel.getAllRecommendLibrary()
        }
    

Since then, the application of an MVVM architecture has been built. After building the MVVM architecture independently for the first time, we have deepened our understanding of the MVVM architecture, and have a new understanding of the components in the JetPack library and other open source libraries. In addition, the MVVM architecture is often used in conjunction with Retrofit, RxJava and other open source libraries. I hope we can practice it again in the future!!

This project uses open source component libraries: koin, timber, permissionx, BaseRecyclerViewAdapterHelper

Video: Advanced MVVM and JetPack in Android

Original text: https://juejin.cn/post/6949876356515627039

Topics: Android MySQL architecture