Android simple MVVM example

This is a demonstration of using Android architectural component ViewModel for a simple MVVM design pattern. It will use RxJava 2, RxKotlin, RxAndroid, Retrofit 2, etc. Github api will be used as example for calling REST service with Retrofit 2. https://api.github.com/users/google

1. Include this at the top of the app gradle file for kotlin compiler.

apply plugin: 'kotlin-kapt'

2. Added these dependencies in the app gradle file.

  //Architecture component
  implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
  kapt 'androidx.lifecycle:lifecycle-compiler:2.0.0'


  //RxJava
  implementation "io.reactivex.rxjava2:rxandroid:2.0.1"
  implementation "io.reactivex.rxjava2:rxjava:2.1.3"
  implementation "io.reactivex.rxjava2:rxkotlin:2.1.0"

  // Retrofit 2
  implementation 'com.squareup.retrofit2:retrofit:2.5.0'
  implementation "com.squareup.retrofit2:adapter-rxjava2:2.5.0"
  implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
  implementation 'com.squareup.okhttp3:logging-interceptor:3.9.0'
  implementation 'com.google.code.gson:gson:2.8.2'

3. Create utility classes for creating Retrofit rest service interface, repository and ViewModel factories.
RestUtil.kt

class RestUtil private constructor() {
    private val API_BASE_URL = "https://api.github.com/"
    val retrofit: Retrofit

    init {
        val interceptor = HttpLoggingInterceptor()
        interceptor.level = HttpLoggingInterceptor.Level.BODY
        val httpClient = OkHttpClient.Builder().addInterceptor(interceptor).build()

        val builder = Retrofit.Builder()
            .baseUrl(API_BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())

        retrofit = builder.client(httpClient).build()
    }

    companion object {
        private var self: RestUtil? = null

        val instance: RestUtil
            get() {
                if (self == null) {
                    synchronized(RestUtil::class.java) {
                        if (self == null) {
                            self =
                                    RestUtil()
                        }
                    }
                }
                return self!!
            }
    }

}

RepositoryFactory.kt

object RepositoryFactory {

    fun createGithubRepository() : GithubRespository {
        val githubApi = RestUtil.instance.retrofit.create(GithubApi::class.java)
        return GithubRespository(githubApi)
    }

}

ViewModelFactory.kt

class ViewModelFactory(private val githubRespository: GithubRespository) : ViewModelProvider.NewInstanceFactory() {

    override fun  create(modelClass: Class): T {
        return MainActivityViewModel(githubRespository) as T
    }

}

4. Create data model, retrofit api interface, and repository.
GithubAccount.kt

data class GithubAccount(
    @SerializedName("login") var login : String = "",
    @SerializedName("id") var id : Int = 0,
    @SerializedName("created_at") var createdAt : String = "",
    @SerializedName("updated_at") var updatedAt : String = "")

GithubApi.kt

interface GithubApi {
    @GET("/users/{username}")
    fun getGithubAccount(@Path("username") username: String): Single>
}

GithubRespository.kt

class GithubRespository(val githubApi: GithubApi) {

    fun fetchGithubAccount(name : String) : Observable {
        return Observable.create { emitter ->

            githubApi.getGithubAccount(name)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe( {
                    if (it.body() != null) {
                        emitter.onNext(it.body()!!)
                    }
                }, {
                    it.printStackTrace()
                })

        }
    }

}

5. Create the ViewModel which uses repository to get data and emit the data to the view through LiveData.

class MainActivityViewModel(val githubRespository: GithubRespository) : ViewModel() {

    private val _githubAccount : MutableLiveData = MutableLiveData()
    val githubAccount : LiveData = _githubAccount

    fun getGithubAccount(name : String) {
        githubRespository
            .fetchGithubAccount(name)
            .subscribe {
                _githubAccount.postValue(it)
            }
    }

}

6. Finally using the ViewModel in the View class, MainActivity.kt

class MainActivity : AppCompatActivity() {

    private lateinit var mainActivityViewModel : MainActivityViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        mainActivityViewModel = ViewModelProviders.of(this, ViewModelFactory(RepositoryFactory.createGithubRepository())).get(MainActivityViewModel::class.java)

        mainActivityViewModel.githubAccount.observe(this, Observer {
            tv_content.text = it.toString()
        })


        mainActivityViewModel.getGithubAccount("google")
    }
}

7. Make sure add the INTERNET permission in the manifest file.


8. The layout file for the MainActivity, activity_main.xml




    


Complete example in Github

Search within Codexpedia

Custom Search

Search the entire web

Custom Search