Android MVVM architecture construction

Posted by impulse() on Tue, 08 Mar 2022 12:51:33 +0100

Although MVVM architecture was also used in previous projects, I was not familiar with the whole MVVM architecture because I didn't 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 relevant 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 of 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 files (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 HomeFragment. The construction parameter of HomeViewModel class is BmobRepository. There is a LiveData variable in the class to carry data. A function getAllRecommendLibrary() obtains open source library data. The function implementation is that repository obtains data in 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 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 and 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 they need 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() }
      }
      
    1. Fragment class implementation:

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

      • The variable homeViewModel is used as 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 the data changes in ViewModel and implements the operation after obtaining the 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 construction of an MVVM architecture has been completed. After the first independent construction of the MVVM architecture, the understanding of the MVVM architecture has deepened a lot, and there is 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 I can practice again in the future!!

Reference article: Android MVVM Architecture - using ViewModel, LiveData, Factory and Repository

Source code of this project android_all_star_app

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

Topics: Java Android Android Studio kotlin