Skip to content

Commit b06bd0b

Browse files
committed
Recycler view example added
1 parent 8958226 commit b06bd0b

File tree

11 files changed

+87
-80
lines changed

11 files changed

+87
-80
lines changed

entities/presentation/src/main/java/ru/sir/presentation/base/recycler_view/BaseViewHolder.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,16 @@ import androidx.databinding.ViewDataBinding
44
import androidx.recyclerview.widget.RecyclerView
55
import ru.sir.presentation.base.BaseViewModel
66

7-
class BaseViewHolder<M, I : RecyclerViewBaseItem<M, out BaseViewModel>>(
7+
class BaseViewHolder<M : Any?, I : RecyclerViewBaseItem<M, out BaseViewModel>>(
88
private val binding: ViewDataBinding,
9-
private val viewModel: I
9+
private val viewModel: I,
10+
private val viewModelId: Int
1011
) : RecyclerView.ViewHolder(binding.root) {
1112

13+
init {
14+
binding.setVariable(viewModelId, viewModel)
15+
}
16+
1217
fun bindData(item: M) {
1318
viewModel.bindData(item)
1419
}
Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,49 @@
11
package ru.sir.presentation.base.recycler_view
22

3+
import android.util.SparseArray
34
import android.view.ViewGroup
45
import androidx.annotation.LayoutRes
56
import androidx.recyclerview.widget.RecyclerView
67
import ru.sir.presentation.base.BaseViewModel
7-
import java.lang.IllegalStateException
88

9-
class RecyclerViewAdapter(private val producers: MutableMap<Int, ViewHolderProducer<*, *, *>>) : RecyclerView.Adapter<BaseViewHolder>() {
9+
class RecyclerViewAdapter(private val producers: SparseArray<ViewHolderProducer<in Any, *, *>>, private val data: MutableList<RecyclerViewBaseDataModel>) : RecyclerView.Adapter<BaseViewHolder<in Any, *>>() {
1010

11-
private var data = mutableListOf<String>()
11+
class Builder<VM : BaseViewModel>(private val viewModel: VM, private val viewModelId: Int) {
12+
private val producers = SparseArray<ViewHolderProducer<*, *, *>>()
1213

13-
class Builder<VM : BaseViewModel>(private val viewModel: VM) {
14-
private val producers = mutableMapOf<Int, ViewHolderProducer<*, *, *>>()
15-
16-
fun <M, I : RecyclerViewBaseItem<M, VM>> addProducer(type: Int, @LayoutRes layoutId: Int, modelClassType: Class<M>, itemViewModelClassType: Class<I>): Builder<VM> {
14+
fun <M : Any, I : RecyclerViewBaseItem<M, VM>> addProducer(
15+
type: Int,
16+
@LayoutRes layoutId: Int,
17+
modelClassType: Class<M>,
18+
itemViewModelClassType: Class<I>
19+
): Builder<VM> {
1720
val producer: ViewHolderProducer<M, I, VM> = ViewHolderProducer(type, layoutId, modelClassType, itemViewModelClassType)
1821
return addProducer(producer)
1922
}
2023

21-
fun <M, I : RecyclerViewBaseItem<M, VM>> addProducer(producer: ViewHolderProducer<M, I, VM>): Builder<VM> {
24+
fun <M : Any, I : RecyclerViewBaseItem<M, VM>> addProducer(producer: ViewHolderProducer<M, I, VM>): Builder<VM> {
2225
producer.setParentViewModel(viewModel)
23-
producers[producer.getViewType()] = producer
26+
producer.setViewModelId(viewModelId)
27+
producers.put(producer.getViewType(), producer)
2428
return this
2529
}
2630

27-
fun build() = RecyclerViewAdapter(producers)
31+
@Suppress("UNCHECKED_CAST")
32+
fun build(data: MutableList<RecyclerViewBaseDataModel>) = RecyclerViewAdapter(producers as SparseArray<ViewHolderProducer<in Any, *, *>>, data)
2833
}
2934

30-
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<*, *> {
35+
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<in Any, *> {
3136
return producers[viewType]?.produce(parent)
3237
?: throw IllegalStateException("View Holder Producer not found!")
3338
}
3439

35-
override fun onBindViewHolder(holder: BaseViewHolder<*, *>, position: Int) {
36-
holder.bindData(data[position])
40+
override fun onBindViewHolder(holder: BaseViewHolder<in Any, *>, position: Int) {
41+
holder.bindData(data[position].getData())
3742
}
3843

3944
override fun getItemCount(): Int = data.size
45+
46+
override fun getItemViewType(position: Int): Int {
47+
return data[position].getType()
48+
}
4049
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package ru.sir.presentation.base.recycler_view
2+
3+
class RecyclerViewBaseDataModel(
4+
private val data: Any,
5+
private val type: Int
6+
) {
7+
8+
fun getData(): Any = data
9+
fun getType(): Int = type
10+
11+
// override fun equals(o: Any?): Boolean {
12+
// if (this === o) return true
13+
// if (o == null || javaClass != o.javaClass) return false
14+
// val that = o as RecyclerViewBaseDataModel
15+
//
16+
// return if (type != that.type) false else Objects.equals(data, that.data)
17+
// }
18+
//
19+
// override fun hashCode(): Int {
20+
// var result = data?.hashCode() ?: 0
21+
// result = 31 * result + type
22+
// return result
23+
// }
24+
}

entities/presentation/src/main/java/ru/sir/presentation/base/recycler_view/RecyclerViewBaseItem.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package ru.sir.presentation.base.recycler_view
22

33
import ru.sir.presentation.base.BaseViewModel
44

5-
abstract class RecyclerViewBaseItem<M, VM : BaseViewModel> {
5+
abstract class RecyclerViewBaseItem<M : Any?, VM : BaseViewModel> {
66
protected lateinit var parent: VM
77

88
fun init(parent: VM) {

entities/presentation/src/main/java/ru/sir/presentation/base/recycler_view/ViewHolderProducer.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,18 @@ import androidx.databinding.DataBindingUtil
77
import androidx.databinding.ViewDataBinding
88
import ru.sir.presentation.base.BaseViewModel
99

10-
class ViewHolderProducer<M, I : RecyclerViewBaseItem<M, VM>, VM : BaseViewModel>(val type: Int, @LayoutRes val layoutId: Int, val modelClassType: Class<M>, private val itemViewModelClassType: Class<I>) {
10+
class ViewHolderProducer<M : Any, I : RecyclerViewBaseItem<M, VM>, VM : BaseViewModel>(val type: Int, @LayoutRes val layoutId: Int, val modelClassType: Class<M>, private val itemViewModelClassType: Class<I>) {
1111
private lateinit var parentViewModel: VM
12+
private var viewModelId: Int = -1
1213

1314
fun setParentViewModel(viewModel: VM) {
1415
parentViewModel = viewModel
1516
}
1617

18+
fun setViewModelId(id: Int) {
19+
viewModelId = id
20+
}
21+
1722
fun getViewType() = type
1823

1924
fun produce(parent: ViewGroup): BaseViewHolder<M, I> {
@@ -24,7 +29,7 @@ class ViewHolderProducer<M, I : RecyclerViewBaseItem<M, VM>, VM : BaseViewModel>
2429
false
2530
)
2631

27-
return BaseViewHolder(binding, instantiateViewModel())
32+
return BaseViewHolder(binding, instantiateViewModel(), viewModelId)
2833
}
2934

3035
private fun instantiateViewModel(): I {

features/example1/src/main/java/ru/bis/example1/view_models/CustomDataBinding.kt renamed to entities/presentation/src/main/java/ru/sir/presentation/extensions/CustomDataBinding.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package ru.bis.example1.view_models
1+
package ru.sir.presentation.extensions
22

33
import androidx.databinding.BindingAdapter
44
import androidx.recyclerview.widget.RecyclerView

features/example1/src/main/java/ru/bis/example1/ui/adapters/Example1Adapter.kt

Lines changed: 0 additions & 28 deletions
This file was deleted.

features/example1/src/main/java/ru/bis/example1/ui/adapters/Example1ViewHolder.kt

Lines changed: 0 additions & 15 deletions
This file was deleted.

features/example1/src/main/java/ru/bis/example1/view_models/Example1ViewModel.kt

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ package ru.bis.example1.view_models
22

33
import android.app.Application
44
import androidx.databinding.ObservableField
5-
import androidx.recyclerview.widget.RecyclerView
5+
import ru.bis.example1.BR
66
import ru.bis.example1.R
7-
import ru.bis.example1.ui.adapters.Example1Adapter
87
import ru.bis.example1_api.interactor.GetDataFromCache
98
import ru.sir.core.None
109
import ru.sir.presentation.base.BaseViewModel
1110
import ru.sir.presentation.base.recycler_view.RecyclerViewAdapter
11+
import ru.sir.presentation.base.recycler_view.RecyclerViewBaseDataModel
1212
import javax.inject.Inject
1313

1414
class Example1ViewModel @Inject constructor(
@@ -17,15 +17,17 @@ class Example1ViewModel @Inject constructor(
1717
) : BaseViewModel(application) {
1818

1919
val result = ObservableField<String>()
20-
val items = mutableListOf<String>()
20+
val items = mutableListOf(
21+
RecyclerViewBaseDataModel("Label 1", 1),
22+
RecyclerViewBaseDataModel("Label 2", 1),
23+
RecyclerViewBaseDataModel("Label 3", 1),
24+
RecyclerViewBaseDataModel("Label 4", 1),
25+
RecyclerViewBaseDataModel("Label 5", 1),
26+
RecyclerViewBaseDataModel("Label 6", 1)
27+
)
2128

2229
override fun init() {
2330
getDataFromCache(None()) { it.either(::onLoadDataFromCacheFailed, ::onLoadDataFromCacheSuccess) }
24-
25-
items.add("String 1")
26-
items.add("String 2")
27-
items.add("String 3")
28-
items.add("String 4")
2931
}
3032

3133
private fun onLoadDataFromCacheSuccess(data: String) {
@@ -36,7 +38,7 @@ class Example1ViewModel @Inject constructor(
3638
result.set(context.getString(R.string.load_data_failed))
3739
}
3840

39-
fun recyclerViewAdapter() = RecyclerViewAdapter.Builder(this)
40-
.addProducer(1, R.layout.item_example1, String::class.java, ItemViewModel::class.java)
41-
.build()
41+
fun recyclerViewAdapter() = RecyclerViewAdapter.Builder(this, BR.viewModel)
42+
.addProducer(1, R.layout.item_example1, String::class.java, ItemViewModel::class.java)
43+
.build(items)
4244
}

features/example1/src/main/res/layout/fragment_example1.xml

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<layout>
2+
<layout xmlns:tools="http://schemas.android.com/tools">
33

44
<data>
55
<variable
@@ -21,27 +21,31 @@
2121
app:layout_constraintEnd_toEndOf="parent"
2222
app:layout_constraintStart_toStartOf="parent"
2323
app:layout_constraintTop_toTopOf="parent"
24-
android:text="@string/example1_title"/>
24+
android:text="@string/example1_title"
25+
android:layout_margin="10dp"/>
2526

2627
<androidx.appcompat.widget.AppCompatTextView
2728
android:id="@+id/text"
2829
android:layout_width="wrap_content"
2930
android:layout_height="wrap_content"
30-
app:layout_constraintBottom_toBottomOf="parent"
31+
app:layout_constraintBottom_toTopOf="@id/rvExample"
3132
app:layout_constraintEnd_toEndOf="parent"
3233
app:layout_constraintStart_toStartOf="parent"
33-
app:layout_constraintTop_toTopOf="parent"
34-
android:text="@{viewModel.result}"/>
34+
app:layout_constraintTop_toBottomOf="@id/title"
35+
android:text="@{viewModel.result}"
36+
android:layout_margin="10dp"/>
3537

3638
<androidx.recyclerview.widget.RecyclerView
39+
android:id="@+id/rvExample"
3740
android:layout_height="0dp"
3841
android:layout_width="match_parent"
3942
app:layout_constraintTop_toBottomOf="@id/text"
4043
app:layout_constraintBottom_toBottomOf="parent"
4144
app:layout_constraintStart_toStartOf="parent"
4245
app:layout_constraintEnd_toEndOf="parent"
43-
recyclerAdapter="@{viewModel.recyclerViewAdapter()}"
44-
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
46+
app:recyclerAdapter="@{viewModel.recyclerViewAdapter()}"
47+
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
48+
tools:listitem="@layout/item_example1"/>
4549

4650
</androidx.constraintlayout.widget.ConstraintLayout>
4751
</layout>

0 commit comments

Comments
 (0)