일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- Android
- rx
- SwiftUI Tutorial
- 테스트 자동화
- Animation
- 동영상
- Koin
- databinding
- android13
- MediaPlayer
- mysql
- 인앱결제
- php
- node.js
- Observable
- RxKotlin
- mvvm
- PagingLib
- paging
- Android 13
- Reactive
- junit
- Kotlin
- MediaSession
- google play
- SWIFTUI
- node
- list
- MotionLayout
- GCP
- Today
- Total
봄날은 갔다. 이제 그 정신으로 공부하자
여러가지 방식으로 List 만들어보기 - part 1 본문
이 글은 MVVM 구조에서 다양한 리스트 사용법에 대해 설명하는 글 입니다.
저는 이글을 통해 다양한 방식으로 리스트를 만들 수 있다는 것을 설명하고자 하는 것으로 반드시 아래 예시에 나와 있는대로 리스트를 만들 필요는 없습니다.
기본 리스트 만들기 (Single item + BindingAdapter)
ViewModel에서 10개의 아이템을 생성해주고 Layout xml에서 BindingAdapter를 사용해 RecyclerView.Adapter와 ViewModel에서 생성한 List Item을 연결해줍니다.
이렇게 사용할 때는 view(Activity)는 별도의 처리를 해주지 않아도 됩니다.
// DefaultViewModel.kt
class DefaultViewModel: BaseViewModel() {
val items: NotNullMutableLiveData<MutableList<DataDefault>> = NotNullMutableLiveData(mutableListOf())
val clickItem : MutableLiveData<DataDefault> = MutableLiveData()
init{
for(idx in 0 .. 9){
items.value.run{
add(DataDefault(idx+1, "Title ${idx+1}", "Description blabla umum…”))
}
}
}
fun onClickItem(data: DataDefault){
clickItem.postValue(data)
}
}
// activity_default.xml
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rcvDefault"
android:layout_width="0dp"
android:layout_height="0dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
baViewModel="@{vmDefault}"
baDefaultListItems="@{vmDefault.items}"
…/>
// BindingAdapter.kt
object BindingAdapterRecyclerView {
…
@BindingAdapter(value = ["baDefaultListItems", "baViewModel"], requireAll = true)
@JvmStatic
fun initDefaultListView(view : RecyclerView, items : List<DataDefault>, vm : DefaultViewModel){
view.adapter?.run {
if (this is ListAdapterDefault) {
this.items = items
this.vm = vm
}
}?: run{
ListAdapterDefault(items, vm)
.apply {
view.adapter = this
}
}
}
…
}
헤더가 포함된 리스트 만들기 (Multi item + BindingAdapter)
기본적인 내용은 위 설명한 기본 리스트 만들기와 동일합니다.
차이가 있는 부분은 RecyclerView.Adapter class로 헤더가 포함된 리스트를 만들려면 아래와 같이 두 개의 ViewHolder를 만들어주고 각 타입에 맞게 Binding 해주어야 합니다.
// ListAdapterMultiItem.kt
class ListAdapterMultiItem(var items : List<DataDefault> = arrayListOf(), var vm : MultiItemViewModel)
: RecyclerView.Adapter<RecyclerView.ViewHolder>(){
companion object{
val HEADER = 0
val ITEM = 1
}
class HeaderViewHolder(val binding: HeaderMultiItemBinding) : RecyclerView.ViewHolder(binding.root)
class ItemViewHolder(val binding: ItemMultiItemBinding) : RecyclerView.ViewHolder(binding.root)
override fun getItemViewType(position: Int): Int {
return when(position){
0 -> HEADER
else -> ITEM
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when(viewType) {
HEADER -> HeaderViewHolder(
DataBindingUtil.inflate(
inflater,
R.layout.header_multi_item,
parent,
false
)
)
else -> ItemViewHolder(
DataBindingUtil.inflate(
inflater,
R.layout.item_multi_item,
parent,
false
)
)
}
}
override fun getItemCount() = items.size+1
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if(getItemViewType(position) == ITEM){
(holder as ItemViewHolder).binding.run {
data = items[position-1]
vmMultiItem = vm
}
}
}
}
헤더가 포함된 리스트 페이징 적용해 만들기 (Multi item + Paging)
여기에서는 BindingAdapter를 사용하지 않고 View에서 ViewModel를 호출해 아이템을 로딩하는 방식으로 만들어보도록 하겠습니다.
우선 app의 build.gradle 파일에 페이징 라이브러리를 추가해 줍니다.
페이징 라이브러리를 추가를 완료하면 ViewModel에 아래와 같이 페이징 라이브러리 관련 인스턴스를 선언 및 정의해줍니다.
이번 예에서는 BindingAdapter를 사용하지 않으므로 layout xml 별다른 처리를 추가히지 않아도 됩니다.
대신 View(Activity)에서 ViewModel의 load() 함수를 호출해 리스트 아이템을 초기화해주어야 합니다.
// MultiPagingViewModel.kt
class MultiPagingViewModel : BaseViewModel() {
val clickItem : MutableLiveData<DataDefault> = MutableLiveData()
val config: PagedList.Config
val pagedListBuilder : LivePagedListBuilder<Int, DataDefault>
init{
config = PagedList.Config.Builder()
.setInitialLoadSizeHint(20)
.setPrefetchDistance(5)
.setPageSize(20)
.build()
pagedListBuilder = LivePagedListBuilder(PagingDefaultDataSource.Factory(), config)
}
fun load(): LiveData<PagedList<DataDefault>> {
return pagedListBuilder.setInitialLoadKey(0).build()
}
fun onClickItem(data: DataDefault){
clickItem.postValue(data)
}
}
// MultiPagingActivity.kt
class MultiPagingActivity: BaseActivity<ActivityMultiPagingBinding>() {
…
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
…
viewDataBinding.vmMultiPaging?.let {vm->
rcvMultiPaging.adapter = ListAdapterMultiPaging(vm)
vm.load()?.observe(this, Observer {pagedList->
(rcvMultiPaging.adapter as ListAdapterMultiPaging).submitList(pagedList)
})
}
}
}
// PagingDefaultDataSource.kt
class PagingDefaultDataSource private constructor(): ItemKeyedDataSource<Int, DataDefault>(){
class Factory: DataSource.Factory<Int, DataDefault>(){
override fun create(): DataSource<Int, DataDefault> {
return PagingDefaultDataSource()
}
}
override fun loadInitial(
params: LoadInitialParams<Int>,
callback: LoadInitialCallback<DataDefault>
) {
callback.onResult(createItems(0, params.requestedLoadSize))
}
override fun loadAfter(params: LoadParams<Int>, callback: LoadCallback<DataDefault>) {
callback.onResult(createItems(params.key, params.requestedLoadSize))
}
override fun loadBefore(params: LoadParams<Int>, callback: LoadCallback<DataDefault>) {
}
override fun getKey(item: DataDefault): Int {
return item.index
}
private fun createItems(offset: Int, loadSize: Int): List<DataDefault>{
val items = mutableListOf<DataDefault>()
for(idx in offset .. (offset+loadSize-1)){
items.add(
DataDefault(
idx+1,
"Title ${idx+1}",
"Description blabla umum..."
)
)
}
return items
}
}
* 참고:
위 설명된 내용에 대한 샘플 소스는 아래 github에 있습니다.
'학습' 카테고리의 다른 글
미디어 앱 아키텍쳐 개요 - part1 (0) | 2020.12.30 |
---|---|
여러가지 방식으로 List 만들어보기 - part 2 (0) | 2020.12.23 |
Google Play 결제 시스템 - Google Play 결제 라이브러리 통합 테스트 (0) | 2020.12.18 |
Google Play 결제 시스템 - 프로모션 코드 (0) | 2020.12.18 |
Google Play 결제 시스템 - 정기 결제 판매 (1) | 2020.12.17 |