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 <T : ViewModel?> create(modelClass: Class<T>): 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<Response<GithubAccount>> }
GithubRespository.kt
class GithubRespository(val githubApi: GithubApi) { fun fetchGithubAccount(name : String) : Observable<GithubAccount> { 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<GithubAccount> = MutableLiveData() val githubAccount : LiveData<GithubAccount> = _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.
<uses-permission android:name="android.permission.INTERNET"/>
8. The layout file for the MainActivity, activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".ui.MainActivity"> <TextView android:id="@+id/tv_content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="" android:gravity="center" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent"/> </androidx.constraintlayout.widget.ConstraintLayout>
No comments:
Post a Comment
Note: only a member of this blog may post a comment.