almost 7 years ago
MVVM stands for model view view-model pattern which helps to separate development of graphic user interface and remove lots of bboilerplatecodes. So in this blog we will help you to use MVVM architecture with rxjava and retrofit in Kotlin or we can say that we will going to implement following features in kotlin project:
Lets see how:
- implementation 'com.squareup.retrofit2:retrofit:2.3.0'
- implementation 'com.android.support:recyclerview-v7:27.1.1'
- implementation 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
- implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
- implementation 'com.jakewharton.rxbinding:rxbinding:0.4.0'
- implementation 'com.google.code.gson:gson:2.8.0'
- implementation "android.arch.lifecycle:extensions:1.1.1"
- annotationProcessor "android.arch.lifecycle:compiler:1.1.1"
implementation 'com.squareup.retrofit2:retrofit:2.3.0' implementation 'com.android.support:recyclerview-v7:27.1.1' implementation 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0' implementation 'com.squareup.retrofit2:converter-gson:2.3.0' implementation 'com.jakewharton.rxbinding:rxbinding:0.4.0' implementation 'com.google.code.gson:gson:2.8.0' implementation "android.arch.lifecycle:extensions:1.1.1" annotationProcessor "android.arch.lifecycle:compiler:1.1.1"
3. Add following compile option to include java8 lambda expressions inside android tag in app.gradle:
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
4. Create api interface to define api call :
5. Create a model class to hold android versions data, In Kotlin we used data class to hold data :
6. Now we create a viewmodel class that will work as a bridge between view and model, it basically prepare observable and that can be observe by view:
- class AndroidViewModel: ViewModel() {
- private val mService = RetrofitService()
- fun getAndroidData() : MutableLiveData<List<Android>>? {
- Log.e("getAndroidData","yes")
- return mService.loadAndroidData()
- }
- }
class AndroidViewModel: ViewModel() { private val mService = RetrofitService() fun getAndroidData() : MutableLiveData<List<Android>>? { Log.e("getAndroidData","yes") return mService.loadAndroidData() } }
7. Now create a common service class for retrofit where we will create a singleton class by using companion object so that only a single instance of Retrofit will generate and method will return a mutable livedata that can be observe by view:
- class RetrofitService {
- val liveUserResponse: MutableLiveData<List<Android>> = MutableLiveData()
- companion object Factory {
- var gson = GsonBuilder().setLenient().create()
- fun create(): ApiInterface {
- Log.e("retrofit","create")
- val retrofit = Retrofit.Builder()
- .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
- .addConverterFactory(GsonConverterFactory.create(gson))
- .baseUrl("https://learn2crack-json.herokuapp.com/api/")
- .build()
- return retrofit.create(ApiInterface::class.java)
- }
- }
- fun loadAndroidData(): MutableLiveData<List<Android>>? {
- Log.e("loadAndroidData","yes")
- val retrofitCall = create().getAndroid()
- retrofitCall.enqueue(object : Callback<List<Android>> {
- override fun onFailure(call: Call<List<Android>>, t: Throwable?) {
- Log.e("on Failure :", "retrofit error")
- }
- override fun onResponse(call: Call<List<Android>>, response: retrofit2.Response<List<Android>>) {
- val list = response.body()
- for (i in list.orEmpty()){
- Log.e("on response 1:", i.name)
- }
- liveUserResponse?.value = list
- Log.e("hasActiveObservers 1", liveUserResponse?.hasActiveObservers().toString()+" check")
- Log.e("on response 2 :", liveUserResponse.toString()+" check")
- }
- })
- return liveUserResponse
- }
- }
class RetrofitService { val liveUserResponse: MutableLiveData<List<Android>> = MutableLiveData() companion object Factory { var gson = GsonBuilder().setLenient().create() fun create(): ApiInterface { Log.e("retrofit","create") val retrofit = Retrofit.Builder() .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create(gson)) .baseUrl("https://learn2crack-json.herokuapp.com/api/") .build() return retrofit.create(ApiInterface::class.java) } } fun loadAndroidData(): MutableLiveData<List<Android>>? { Log.e("loadAndroidData","yes") val retrofitCall = create().getAndroid() retrofitCall.enqueue(object : Callback<List<Android>> { override fun onFailure(call: Call<List<Android>>, t: Throwable?) { Log.e("on Failure :", "retrofit error") } override fun onResponse(call: Call<List<Android>>, response: retrofit2.Response<List<Android>>) { val list = response.body() for (i in list.orEmpty()){ Log.e("on response 1:", i.name) } liveUserResponse?.value = list Log.e("hasActiveObservers 1", liveUserResponse?.hasActiveObservers().toString()+" check") Log.e("on response 2 :", liveUserResponse.toString()+" check") } }) return liveUserResponse } }
we are using learn2crack api to show all android versions in a recyclerview.
8. MainActivity to show android versions in a recyclerview :
- class MainActivity : AppCompatActivity() {
- private lateinit var linearLayoutManager: LinearLayoutManager
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
- linearLayoutManager = LinearLayoutManager(this@MainActivity)
- recyclerView.layoutManager = linearLayoutManager
- recyclerView.hasFixedSize()
- getAndroidVersion()
- }
- private fun getAndroidVersion() {
- Log.e("getAndroidVersion","yes")
- val mAndroidViewModel = ViewModelProviders.of(this@MainActivity).get(AndroidViewModel::class.java)
- mAndroidViewModel.getAndroidData()?.observe(this, Observer<List<Android>> { androidList ->
- Log.e("list",androidList?.size.toString())
- recyclerView.adapter = EmpAdapter(this@MainActivity, androidList as ArrayList<Android>, object : ItemClickListener {
- override fun onItemClick(pos: Int) {
- Toast.makeText(applicationContext, "item $pos clicked", Toast.LENGTH_LONG).show()
- }
- })
- })
- }
- }
class MainActivity : AppCompatActivity() { private lateinit var linearLayoutManager: LinearLayoutManager override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) linearLayoutManager = LinearLayoutManager(this@MainActivity) recyclerView.layoutManager = linearLayoutManager recyclerView.hasFixedSize() getAndroidVersion() } private fun getAndroidVersion() { Log.e("getAndroidVersion","yes") val mAndroidViewModel = ViewModelProviders.of(this@MainActivity).get(AndroidViewModel::class.java) mAndroidViewModel.getAndroidData()?.observe(this, Observer<List<Android>> { androidList -> Log.e("list",androidList?.size.toString()) recyclerView.adapter = EmpAdapter(this@MainActivity, androidList as ArrayList<Android>, object : ItemClickListener { override fun onItemClick(pos: Int) { Toast.makeText(applicationContext, "item $pos clicked", Toast.LENGTH_LONG).show() } }) }) } }
9. Now creating adapter to fill data in recyclerview, here we will use rxjava click feature
- class EmpAdapter(var context: MainActivity, var mEmpList: ArrayList<Android>, private val itemClick:ItemClickListener): RecyclerView.Adapter<EmpAdapter.EmpHolder>() {
- companion object {
- var mItemClickListener : ItemClickListener? = null
- }
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EmpHolder {
- val view = LayoutInflater.from(context).inflate(R.layout.items, parent, false)
- return EmpHolder(view)
- }
- override fun getItemCount(): Int {
- return mEmpList.size
- }
- override fun onBindViewHolder(holder:EmpHolder, position: Int) {
- mItemClickListener = itemClick
- holder.tvFname?.text = mEmpList[position].name
- holder.tvLname?.text = mEmpList[position].apiLevel
- RxView.clicks(holder.mView).subscribe {
- mItemClickListener!!.onItemClick(position)
- }
- }
- class EmpHolder (view: View) : RecyclerView.ViewHolder(view) {
- val tvFname = view.tvFname
- val tvLname = view.tvLname
- val mView = view
- }
- }
class EmpAdapter(var context: MainActivity, var mEmpList: ArrayList<Android>, private val itemClick:ItemClickListener): RecyclerView.Adapter<EmpAdapter.EmpHolder>() { companion object { var mItemClickListener : ItemClickListener? = null } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EmpHolder { val view = LayoutInflater.from(context).inflate(R.layout.items, parent, false) return EmpHolder(view) } override fun getItemCount(): Int { return mEmpList.size } override fun onBindViewHolder(holder:EmpHolder, position: Int) { mItemClickListener = itemClick holder.tvFname?.text = mEmpList[position].name holder.tvLname?.text = mEmpList[position].apiLevel RxView.clicks(holder.mView).subscribe { mItemClickListener!!.onItemClick(position) } } class EmpHolder (view: View) : RecyclerView.ViewHolder(view) { val tvFname = view.tvFname val tvLname = view.tvLname val mView = view } }
10. Interface for click event :
You can also download the whole sample project here :
https://github.com/rohitpuriji/Kotlin-MVVM
Post you comment for any query.
Thanks.
0 Comment(s)