Coverage Summary for Class: BaseRcvListAdapter (kr.open.library.simple_ui.xml.ui.adapter.list.base)
| Class |
Class, %
|
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
| BaseRcvListAdapter |
100%
(1/1)
|
91.7%
(33/36)
|
84.2%
(32/38)
|
93.6%
(88/94)
|
92.3%
(512/555)
|
package kr.open.library.simple_ui.xml.ui.adapter.list.base
import android.view.View
import android.view.ViewGroup
import androidx.annotation.MainThread
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import kr.open.library.simple_ui.core.extensions.trycatch.safeCatch
import kr.open.library.simple_ui.core.logcat.Logx
import kr.open.library.simple_ui.xml.ui.adapter.common.AdapterCommonClickData
import kr.open.library.simple_ui.xml.ui.adapter.common.AdapterCommonDataLogic
import kr.open.library.simple_ui.xml.ui.adapter.common.imp.AdapterClickable
import kr.open.library.simple_ui.xml.ui.adapter.common.imp.AdapterReadApi
import kr.open.library.simple_ui.xml.ui.adapter.common.imp.AdapterWriteApi
import kr.open.library.simple_ui.xml.ui.adapter.common.thread.assertAdapterMainThread
import kr.open.library.simple_ui.xml.ui.adapter.list.base.diffutil.RcvListDiffUtilCallBack
import kr.open.library.simple_ui.xml.ui.adapter.list.base.queue.AdapterOperationQueue
import kr.open.library.simple_ui.xml.ui.adapter.list.base.queue.QueueOverflowPolicy
import kr.open.library.simple_ui.xml.ui.adapter.list.base.result.ListAdapterResult
import kr.open.library.simple_ui.xml.ui.adapter.list.base.result.toAdapterDropReason
import kr.open.library.simple_ui.xml.ui.adapter.list.base.result.toListAdapterResult
import kr.open.library.simple_ui.xml.ui.adapter.viewholder.BaseRcvViewHolder
/**
* Base RecyclerView ListAdapter implementation with queue-based operations.<br>
* 큐 기반 연산을 제공하는 기본 RecyclerView ListAdapter 구현입니다.<br>
* Provides comprehensive item management and click handling functionality.<br><br>
* 아이템 관리와 클릭 처리 기능을 포괄적으로 제공합니다.<br>
*
* Features:<br>
* 주요 기능:<br>
* - DiffUtil-based efficient list updates<br>
* - DiffUtil 기반의 효율적인 리스트 업데이트를 지원합니다.<br>
* - Queue-based consecutive operations handling<br>
* - 큐 기반 연속 연산 처리를 지원합니다.<br>
* - Item click and long-click listener support<br>
* - 아이템 클릭/롱클릭 리스너를 지원합니다.<br>
* - Add, remove, move, replace item operations<br>
* - 아이템 추가/제거/이동/교체 연산을 지원합니다.<br>
* - Partial update support via payloads<br>
* - payload 기반 부분 업데이트를 지원합니다.<br>
* - Automatic ViewHolder cache clearing<br><br>
* - ViewHolder 캐시 자동 정리를 지원합니다.<br>
*
* Usage example:<br>
* 사용 예시:<br>
* ```kotlin
* class MyAdapter : BaseRcvListAdapter<MyItem, MyViewHolder>(MyDiffUtil()) {
* override fun createViewHolderInternal(parent: ViewGroup, viewType: Int): MyViewHolder {
* return MyViewHolder(LayoutInflater.from(parent.context)
* .inflate(R.layout.item_layout, parent, false))
* }
*
* override fun onBindViewHolder(holder: MyViewHolder, item: MyItem, position: Int) {
* holder.bind(item)
* }
* }
* ```
* <br>
* 예시 코드를 참고해 구현 패턴을 적용할 수 있습니다.<br>
*
* @param ITEM The type of items in the list.<br><br>
* 리스트의 아이템 타입입니다.<br>
*
* @param VH The type of ViewHolder.<br><br>
* ViewHolder 타입입니다.<br>
*
* @param listDiffUtil DiffUtil callback for comparing items.<br><br>
* 아이템 비교를 위한 DiffUtil 콜백입니다.<br>
*
* @see RcvListDiffUtilCallBack For the DiffUtil callback implementation.<br><br>
* DiffUtil 콜백 구현은 RcvListDiffUtilCallBack을 참고하세요.<br>
*
* @see AdapterOperationQueue For the operation queue implementation.<br><br>
* 연산 큐 구현은 AdapterOperationQueue를 참고하세요.<br>
*/
public abstract class BaseRcvListAdapter<ITEM, VH : RecyclerView.ViewHolder>(
listDiffUtil: RcvListDiffUtilCallBack<ITEM>,
) : ListAdapter<ITEM, VH>(listDiffUtil),
AdapterReadApi<ITEM>,
AdapterWriteApi<ITEM, ListAdapterResult>,
AdapterClickable<ITEM, VH> {
private val commonDataLogic = AdapterCommonDataLogic<ITEM>()
private val clickData = AdapterCommonClickData<ITEM, VH>()
/**
* Operation queue for handling consecutive adapter operations.<br>
* 연속된 adapter 연산을 처리하는 operation queue입니다.<br>
* Ensures operations are executed in order and prevents conflicts.<br><br>
* 연산 순서를 보장하고 충돌을 방지합니다.<br>
*/
private val operationQueue = AdapterOperationQueue<ITEM>(
getCurrentList = { currentList },
applyList = { _, _, updatedList, callback -> submitList(updatedList, callback) },
)
/**
* Sets queue overflow policy and max pending size.<br><br>
* 큐 오버플로 정책과 최대 대기 크기를 설정합니다.<br>
*
* @param maxPending Maximum number of pending operations allowed.<br><br>
* 허용되는 최대 대기 연산 수입니다.<br>
*
* @param overflowPolicy Overflow handling policy when queue is full.<br><br>
* 큐가 가득 찼을 때 적용할 오버플로 정책입니다.<br>
*/
public fun setQueuePolicy(maxPending: Int, overflowPolicy: QueueOverflowPolicy) {
assertMainThread("BaseRcvListAdapter.setQueuePolicy")
operationQueue.setQueuePolicy(maxPending, overflowPolicy)
}
/**
* Creates a ViewHolder and attaches click listeners once.<br><br>
* ViewHolder를 생성하고 클릭 리스너를 1회 연결합니다.<br>
*/
public final override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
val holder = createViewHolderInternal(parent, viewType)
bindClickListener(holder)
return holder
}
/**
* Attaches click/long-click listeners once and keeps adapter index mapping as-is.<br><br>
* 클릭/롱클릭 리스너를 1회 부착하고 adapter 인덱스를 그대로 사용합니다.<br>
*/
private fun bindClickListener(holder: VH) {
clickData.attachClickListeners(
holder = holder,
positionMapper = { adapterPosition -> adapterPosition },
itemProvider = { position -> getItemOrNull(position) },
)
clickData.attachLongClickListeners(
holder = holder,
positionMapper = { adapterPosition -> adapterPosition },
itemProvider = { position -> getItemOrNull(position) },
)
}
/**
* Creates a ViewHolder for the given parent and view type.<br><br>
* 부모 View와 viewType에 맞는 ViewHolder를 생성합니다.<br>
*/
protected abstract fun createViewHolderInternal(parent: ViewGroup, viewType: Int): VH
/**
* onBindViewHolder for partial updates with payload support.<br>
* payload를 지원하는 부분 업데이트용 onBindViewHolder입니다.<br>
* By default performs full binding. Override to implement partial updates.<br><br>
* 기본 구현은 전체 바인딩이며, 부분 업데이트가 필요하면 오버라이드합니다.<br>
*
* @param holder The ViewHolder to bind data to.<br><br>
* 데이터를 바인딩할 ViewHolder입니다.<br>
*
* @param position The position of the item in the list.<br><br>
* 리스트에서 아이템 위치입니다.<br>
*
* @param item The item to bind.<br><br>
* 바인딩할 아이템입니다.<br>
*
* @param payloads The list of payloads for partial updates.<br><br>
* 부분 업데이트를 위한 payload 목록입니다.<br>
*/
protected open fun onBindViewHolder(holder: VH, item: ITEM, position: Int, payloads: List<Any>) {
// By default performs full binding
onBindViewHolder(holder, item, position)
}
/**
* Returns the current item list set in the adapter.<br><br>
* 현재 adapter에 설정된 아이템 리스트를 반환합니다.<br>
*
* @return The current item list.<br><br>
* 현재 아이템 리스트를 반환합니다.<br>
*/
@MainThread
public override fun getItems(): List<ITEM> = runOnMainThread("BaseRcvListAdapter.getItems") { currentList }
/**
* Returns the index of [item] within the current list.<br><br>
* 현재 리스트에서 [item]의 인덱스를 반환합니다.<br>
*
* @param item Target item to find.<br><br>
* 조회할 대상 아이템입니다.<br>
* @return The index if found, otherwise -1.<br><br>
* 아이템이 존재하면 인덱스, 없으면 -1을 반환합니다.<br>
*/
@MainThread
override fun getItemPosition(item: ITEM): Int =
runOnMainThread("BaseRcvListAdapter.getItemPosition") { currentList.indexOf(item) }
/**
* Returns a mutable copy of the current item list.<br>
* 현재 아이템 리스트의 가변 복사본을 반환합니다.<br>
* **Warning**: This is a snapshot copy. Mutations do NOT affect the adapter state.<br>
* 경고: 이 리스트는 스냅샷 복사본이며 변경해도 adapter 상태에 반영되지 않습니다.<br>
* To update the adapter, pass the modified list to [setItems] explicitly.<br><br>
* adapter를 갱신하려면 수정된 리스트를 [setItems]에 명시적으로 전달해야 합니다.<br>
*
* @return A mutable copy of the current item list.<br><br>
* 현재 아이템 리스트의 가변 복사본을 반환합니다.<br>
*/
@MainThread
public override fun getMutableItemList(): MutableList<ITEM> =
runOnMainThread("BaseRcvListAdapter.getMutableItemList") { currentList.toMutableList() }
/**
* Sets the item list.<br>
* 아이템 리스트를 설정합니다.<br>
* Cancels all pending queue operations and replaces with the new list.<br><br>
* 대기 중인 큐 연산을 취소하고 새 리스트로 교체합니다.<br>
*
* @param items The item list to set.<br><br>
* 설정할 아이템 리스트입니다.<br>
*
* @param onResult Callback invoked when the queue operation reaches terminal state (nullable).<br><br>
* 큐 연산이 종료 상태에 도달하면 호출되는 결과 콜백입니다(null 가능).<br>
*/
@MainThread
public override fun setItems(items: List<ITEM>, onResult: ((ListAdapterResult) -> Unit)?) {
assertMainThread("BaseRcvListAdapter.setItems")
operationQueue.clearQueueAndExecute(AdapterOperationQueue.SetItemsOp(items, toOperationCallback(onResult)))
}
/**
* Adds an item to the end of the list.<br><br>
* 리스트 끝에 아이템을 추가합니다.<br>
*
* @param item The item to add.<br><br>
* 추가할 아이템입니다.<br>
*
* @param onResult Callback invoked when the queue operation reaches terminal state (nullable).<br><br>
* 큐 연산이 종료 상태에 도달하면 호출되는 결과 콜백입니다(null 가능).<br>
*/
@MainThread
public override fun addItem(item: ITEM, onResult: ((ListAdapterResult) -> Unit)?) {
assertMainThread("BaseRcvListAdapter.addItem")
operationQueue.enqueueOperation(AdapterOperationQueue.AddItemOp(item, toOperationCallback(onResult)))
}
/**
* Adds an item at a specific position.<br><br>
* 지정한 위치에 아이템을 추가합니다.<br>
*
* @param position The position to add the item at.<br><br>
* 아이템을 추가할 위치입니다.<br>
*
* @param item The item to add.<br><br>
* 추가할 아이템입니다.<br>
*
* @param onResult Callback invoked when the queue operation reaches terminal state (nullable).<br><br>
* 큐 연산이 종료 상태에 도달하면 호출되는 결과 콜백입니다(null 가능).<br>
*/
@MainThread
public override fun addItemAt(position: Int, item: ITEM, onResult: ((ListAdapterResult) -> Unit)?) {
val failure = commonDataLogic.validateAddItemAt(position, itemCount)
if (failure != null) {
runResultCallback(failure.toListAdapterResult(), onResult)
return
}
operationQueue.enqueueOperation(AdapterOperationQueue.AddItemAtOp(position, item, toOperationCallback(onResult)))
}
/**
* Adds multiple items to the end of the list.<br><br>
* 리스트 끝에 여러 아이템을 추가합니다.<br>
*
* @param items The list of items to add.<br><br>
* 추가할 아이템 목록입니다.<br>
*
* @param onResult Callback invoked when the queue operation reaches terminal state (nullable).<br><br>
* 큐 연산이 종료 상태에 도달하면 호출되는 결과 콜백입니다(null 가능).<br>
*/
@MainThread
public override fun addItems(items: List<ITEM>, onResult: ((ListAdapterResult) -> Unit)?) {
val failure = commonDataLogic.validateAddItems(items)
if (failure != null) {
runResultCallback(failure.toListAdapterResult(), onResult)
return
}
operationQueue.enqueueOperation(AdapterOperationQueue.AddItemsOp(items, toOperationCallback(onResult)))
}
/**
* Inserts multiple items at a specific position.<br><br>
* 지정한 위치에 여러 아이템을 삽입합니다.<br>
*
* @param position The position to insert items at.<br><br>
* 아이템들을 삽입할 위치입니다.<br>
*
* @param items The list of items to insert.<br><br>
* 삽입할 아이템 목록입니다.<br>
*
* @param onResult Callback invoked when the queue operation reaches terminal state (nullable).<br><br>
* 큐 연산이 종료 상태에 도달하면 호출되는 결과 콜백입니다(null 가능).<br>
*/
@MainThread
public override fun addItemsAt(position: Int, items: List<ITEM>, onResult: ((ListAdapterResult) -> Unit)?) {
val failure = commonDataLogic.validateAddItemsAt(items, position, itemCount)
if (failure != null) {
runResultCallback(failure.toListAdapterResult(), onResult)
return
}
operationQueue.enqueueOperation(AdapterOperationQueue.AddItemsAtOp(position, items, toOperationCallback(onResult)))
}
/**
* Checks if the position is valid.<br><br>
* position 유효성을 확인합니다.<br>
*
* @param position The position to check.<br><br>
* 확인할 위치입니다.<br>
*
* @return True if position is valid, false otherwise.<br><br>
* 위치가 유효하면 true, 아니면 false를 반환합니다.<br>
*/
protected fun isPositionValid(position: Int): Boolean = commonDataLogic.isPositionValid(position, itemCount)
/**
* Removes a specific item from the list.<br><br>
* 리스트에서 특정 아이템을 제거합니다.<br>
*
* @param item The item to remove.<br><br>
* 제거할 아이템입니다.<br>
*
* @param onResult Callback invoked when the queue operation reaches terminal state (nullable).<br><br>
* 큐 연산이 종료 상태에 도달하면 호출되는 결과 콜백입니다(null 가능).<br>
*/
@MainThread
public override fun removeItem(item: ITEM, onResult: ((ListAdapterResult) -> Unit)?) {
val failure = commonDataLogic.validateRemoveItem(item, currentList)
if (failure != null) {
runResultCallback(failure.toListAdapterResult(), onResult)
return
}
operationQueue.enqueueOperation(AdapterOperationQueue.RemoveItemOp(item, toOperationCallback(onResult)))
}
/**
* Removes the item at a specific position.<br><br>
* 지정한 위치의 아이템을 제거합니다.<br>
*
* @param position The position of the item to remove.<br><br>
* 제거할 아이템의 위치입니다.<br>
*
* @param onResult Callback invoked when the queue operation reaches terminal state (nullable).<br><br>
* 큐 연산이 종료 상태에 도달하면 호출되는 결과 콜백입니다(null 가능).<br>
*/
@MainThread
public override fun removeAt(position: Int, onResult: ((ListAdapterResult) -> Unit)?) {
val failure = commonDataLogic.validateRemoveItemAt(position, itemCount)
if (failure != null) {
runResultCallback(failure.toListAdapterResult(), onResult)
return
}
operationQueue.enqueueOperation(AdapterOperationQueue.RemoveAtOp(position, toOperationCallback(onResult)))
}
/**
* Removes all items from the list.<br><br>
* 리스트의 모든 아이템을 제거합니다.<br>
*
* @param onResult Callback invoked when the queue operation reaches terminal state (nullable).<br><br>
* 큐 연산이 종료 상태에 도달하면 호출되는 결과 콜백입니다(null 가능).<br>
*/
@MainThread
public override fun removeAll(onResult: ((ListAdapterResult) -> Unit)?) {
assertMainThread("BaseRcvListAdapter.removeAll")
operationQueue.enqueueOperation(AdapterOperationQueue.ClearItemsOp(toOperationCallback(onResult)))
}
/**
* Removes matching items from current list.<br>
* 현재 리스트에서 일치하는 아이템을 제거합니다.<br>
* This method uses best-effort semantics and removes only existing matches.<br><br>
* best-effort 방식으로 실제 존재하는 항목만 제거합니다.<br>
*
* @param items Items requested to remove.<br><br>
* 제거 요청한 아이템 목록입니다.<br>
* @param onResult Callback invoked when the queue operation reaches terminal state (nullable).<br><br>
* 큐 연산이 종료 상태에 도달하면 호출되는 결과 콜백입니다(null 가능).<br>
*/
@MainThread
override fun removeItems(items: List<ITEM>, onResult: ((ListAdapterResult) -> Unit)?) {
val failure = commonDataLogic.validateRemoveItems(items, currentList)
if (failure != null) {
runResultCallback(failure.toListAdapterResult(), onResult)
return
}
operationQueue.enqueueOperation(AdapterOperationQueue.RemoveItemsOp(items, toOperationCallback(onResult)))
}
/**
* Removes a contiguous range using start index and count.<br><br>
* 시작 인덱스와 개수 기준으로 연속 구간을 제거합니다.<br>
*
* Example: start=3, count=2 removes indices 3 and 4.<br><br>
* 예: start=3, count=2이면 인덱스 3, 4를 제거합니다.<br>
*
* @param start Start index of range to remove.<br><br>
* 제거 범위의 시작 인덱스입니다.<br>
* @param count Number of items to remove from start.<br><br>
* start부터 제거할 아이템 개수입니다.<br>
* @param onResult Callback invoked when the queue operation reaches terminal state (nullable).<br><br>
* 큐 연산이 종료 상태에 도달하면 호출되는 결과 콜백입니다(null 가능).<br>
*/
@MainThread
override fun removeRange(start: Int, count: Int, onResult: ((ListAdapterResult) -> Unit)?) {
val failure = commonDataLogic.validateRemoveRange(start, count, itemCount)
if (failure != null) {
runResultCallback(failure.toListAdapterResult(), onResult)
return
}
operationQueue.enqueueOperation(AdapterOperationQueue.RemoveRangeOp(start, count, toOperationCallback(onResult)))
}
/**
* Moves an item from one position to another.<br><br>
* 아이템을 한 위치에서 다른 위치로 이동합니다.<br>
*
* @param fromPosition The current position of the item to move.<br><br>
* 이동할 아이템의 현재 위치입니다.<br>
*
* @param toPosition The target position to move the item to.<br><br>
* 아이템을 이동할 목표 위치입니다.<br>
*
* @param onResult Callback invoked when the queue operation reaches terminal state (nullable).<br><br>
* 큐 연산이 종료 상태에 도달하면 호출되는 결과 콜백입니다(null 가능).<br>
*/
@MainThread
public override fun moveItem(fromPosition: Int, toPosition: Int, onResult: ((ListAdapterResult) -> Unit)?) {
val failure = commonDataLogic.validateMoveItem(fromPosition, toPosition, itemCount)
if (failure != null) {
runResultCallback(failure.toListAdapterResult(), onResult)
return
}
operationQueue.enqueueOperation(AdapterOperationQueue.MoveItemOp(fromPosition, toPosition, toOperationCallback(onResult)))
}
/**
* Replaces the item at a specific position with a new item.<br><br>
* 지정한 위치의 아이템을 새 아이템으로 교체합니다.<br>
*
* @param position The position of the item to replace.<br><br>
* 교체할 아이템의 위치입니다.<br>
*
* @param item The new item to replace with.<br><br>
* 교체할 새 아이템입니다.<br>
*
* @param onResult Callback invoked when the queue operation reaches terminal state (nullable).<br><br>
* 큐 연산이 종료 상태에 도달하면 호출되는 결과 콜백입니다(null 가능).<br>
*/
@MainThread
public override fun replaceItemAt(position: Int, item: ITEM, onResult: ((ListAdapterResult) -> Unit)?) {
val failure = commonDataLogic.validateReplaceItemAt(position, itemCount)
if (failure != null) {
runResultCallback(failure.toListAdapterResult(), onResult)
return
}
operationQueue.enqueueOperation(AdapterOperationQueue.ReplaceItemAtOp(position, item, toOperationCallback(onResult)))
}
/**
* Abstract bind contract for subclasses.<br><br>
* 하위 클래스가 구현해야 하는 바인딩 계약입니다.<br>
*
* @param holder The ViewHolder to bind.<br><br>
* 바인딩 대상 ViewHolder입니다.<br>
* @param item Item resolved for the given position.<br><br>
* item 파라미터입니다.<br>
* @param position Current adapter position.<br><br>
* 현재 adapter 위치입니다.<br>
*/
protected abstract fun onBindViewHolder(holder: VH, item: ITEM, position: Int)
/**
* Safely returns the item at the position or null.<br><br>
* position의 아이템을 안전하게 조회하고 없으면 null을 반환합니다.<br>
*/
@MainThread
public override fun getItemOrNull(position: Int): ITEM? =
runOnMainThread("BaseRcvListAdapter.getItemOrNull") { currentList.getOrNull(position) }
/**
* Sets the item click listener.<br><br>
* 아이템 클릭 리스너를 설정합니다.<br>
*
* @param listener The callback for click events (receives position, item, and view).<br><br>
* 클릭 이벤트 콜백입니다(position, item, view 전달).<br>
*/
@MainThread
public override fun setOnItemClickListener(listener: (Int, ITEM, View) -> Unit) {
assertMainThread("BaseRcvListAdapter.setOnItemClickListener")
clickData.onItemClickListener = listener
}
/**
* Sets the item long-click listener.<br><br>
* 아이템 롱클릭 리스너를 설정합니다.<br>
*
* @param listener The callback for long-click events (receives position, item, and view).<br><br>
* 롱클릭 이벤트 콜백입니다(position, item, view 전달).<br>
*/
@MainThread
public override fun setOnItemLongClickListener(listener: (Int, ITEM, View) -> Unit) {
assertMainThread("BaseRcvListAdapter.setOnItemLongClickListener")
clickData.onItemLongClickListener = listener
}
/**
* Binds data to the ViewHolder at the specified position.<br><br>
* 지정한 위치의 ViewHolder에 데이터를 바인딩합니다.<br>
*
* @param holder The ViewHolder to bind.<br><br>
* 바인딩 대상 ViewHolder입니다.<br>
*
* @param position The position of the item.<br><br>
* 아이템 위치입니다.<br>
*/
override fun onBindViewHolder(holder: VH, position: Int) {
if (!isPositionValid(position)) {
Logx.e("Invalid position: $position, item count: $itemCount")
return
}
onBindViewHolder(holder, getItem(position), position)
}
/**
* Binds data to the ViewHolder with payload support.<br>
* payload를 사용해 ViewHolder 데이터를 바인딩합니다.<br>
* Performs full binding if payloads is empty, otherwise partial update.<br><br>
* payload가 비어 있으면 전체 바인딩, 아니면 부분 업데이트를 수행합니다.<br>
*
* @param holder The ViewHolder to bind.<br><br>
* 바인딩 대상 ViewHolder입니다.<br>
*
* @param position The position of the item.<br><br>
* 아이템 위치입니다.<br>
*
* @param payloads The list of payloads for partial updates.<br><br>
* 부분 업데이트를 위한 payload 목록입니다.<br>
*/
override fun onBindViewHolder(holder: VH, position: Int, payloads: MutableList<Any>) {
if (payloads.isEmpty()) {
// Full binding if no payloads
onBindViewHolder(holder, position)
} else {
// Partial update if payloads exist
if (!isPositionValid(position)) {
Logx.e("Invalid position: $position, item count: $itemCount")
return
}
getItemOrNull(position)?.let { onBindViewHolder(holder, it, position, payloads) }
}
}
/**
* Asserts Main thread and then executes [block].<br><br>
* 메인 스레드를 검증한 뒤 [block]을 실행합니다.<br>
*/
private inline fun <T> runOnMainThread(apiName: String, block: () -> T): T {
assertAdapterMainThread(apiName)
return block()
}
/**
* Asserts that the current call is on Main thread.<br><br>
* 현재 호출이 메인 스레드인지 검증합니다.<br>
*/
private fun assertMainThread(apiName: String) {
assertAdapterMainThread(apiName)
}
/**
* Safely invokes a result callback with the supplied result value.<br><br>
* 전달된 결과 값으로 결과 콜백을 안전하게 호출합니다.<br>
*/
private fun runResultCallback(result: ListAdapterResult, onResult: ((ListAdapterResult) -> Unit)?) = safeCatch {
onResult?.invoke(result)
}
/**
* Creates an operation callback that maps queue terminal states to public list results.<br><br>
* 큐 종료 상태를 공개 list 결과로 변환하는 연산 콜백을 생성합니다.<br>
* Returns null when [onResult] is null, so that no callback is registered in the queue.<br><br>
* [onResult]가 null이면 null을 반환하여 큐에 콜백을 등록하지 않습니다.<br>
*/
private fun toOperationCallback(onResult: ((ListAdapterResult) -> Unit)?): ((AdapterOperationQueue.OperationTerminalState) -> Unit)? {
if (onResult == null) return null
return { terminalState -> runResultCallback(terminalState.toListAdapterResult(), onResult) }
}
/**
* Maps queue terminal states to public list adapter results.<br><br>
* 큐 종료 상태를 공개 list adapter 결과로 변환합니다.<br>
*/
private fun AdapterOperationQueue.OperationTerminalState.toListAdapterResult(): ListAdapterResult = when (this) {
is AdapterOperationQueue.OperationTerminalState.Applied -> ListAdapterResult.Applied
is AdapterOperationQueue.OperationTerminalState.Dropped -> ListAdapterResult.Failed.Dropped(reason.toAdapterDropReason())
is AdapterOperationQueue.OperationTerminalState.ExecutionError -> ListAdapterResult.Failed.ExecutionError(cause)
}
/**
* Called when a ViewHolder is recycled.<br>
* ViewHolder가 재활용될 때 호출됩니다.<br>
* Clears the view cache if the holder is a BaseRcvViewHolder.<br><br>
* holder가 BaseRcvViewHolder이면 뷰 캐시를 정리합니다.<br>
*
* @param holder The ViewHolder being recycled.<br><br>
* 재활용되는 ViewHolder입니다.<br>
*/
override fun onViewRecycled(holder: VH) {
super.onViewRecycled(holder)
if (holder is BaseRcvViewHolder) {
holder.clearViewCache()
}
}
}