Skip to content

Commit

Permalink
Issue boostcampwm-2021#104 feat: ViewPager in RecyclerView 성능 개선을 위해 …
Browse files Browse the repository at this point in the history
…코루틴 적용, ListAdapter 제거

-  GridLayoutManager가 diffUtils를 사용할 때 역순으로 binding되는 문제 때문에 ListAdapter 제거
- 달력 생성 및 binding할 때 UI delay를 줄이기 위해 코루틴 적용 (임시 해결책 근본적인 해결이 필요)
  • Loading branch information
PsPLoG committed Nov 10, 2021
1 parent dbcf85f commit bc2b169
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ package com.drunkenboys.ckscalendar.month

import android.graphics.Color
import android.text.TextUtils
import android.util.Log
import android.util.TypedValue
import android.view.Gravity
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.drunkenboys.ckscalendar.data.CalendarDate
import com.drunkenboys.ckscalendar.data.CalendarDesignObject
Expand All @@ -21,11 +21,19 @@ import com.drunkenboys.ckscalendar.listener.OnDaySecondClickListener
import com.drunkenboys.ckscalendar.utils.context
import com.drunkenboys.ckscalendar.utils.dp2px
import com.drunkenboys.ckscalendar.utils.tintStroke
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class MonthAdapter(val onDaySelectStateListener: OnDaySelectStateListener) : ListAdapter<CalendarDate, MonthAdapter.Holder>(diffUtil) {
class MonthAdapter(val onDaySelectStateListener: OnDaySelectStateListener) : RecyclerView.Adapter<MonthAdapter.Holder>() {

private var timeTest = 0L

private val schedules = mutableListOf<CalendarScheduleObject>()

private val currentList = mutableListOf<CalendarDate>()

private lateinit var calendarDesign: CalendarDesignObject

var selectedPosition = -1
Expand Down Expand Up @@ -54,7 +62,11 @@ class MonthAdapter(val onDaySelectStateListener: OnDaySelectStateListener) : Lis
this.currentPagePosition = currentPagePosition
this.schedules.clear()
this.schedules.addAll(schedules)
submitList(list)
this.currentList.clear()
this.currentList.addAll(list)
timeTest = System.currentTimeMillis()
Log.e(this::class.simpleName, "setItems")
notifyDataSetChanged()
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
Expand Down Expand Up @@ -100,14 +112,18 @@ class MonthAdapter(val onDaySelectStateListener: OnDaySelectStateListener) : Lis
}
binding.tvMonthDay.setTextColor(textColor)

binding.layoutMonthSchedule.removeAllViews()
val scheduleContainer = makePaddingScheduleList(item, schedules)
val hasAnySchedule = scheduleContainer.any { it != null }
if (hasAnySchedule) {
scheduleContainer.map { it ?: makeDefaultScheduleTextView() }
.forEach {
binding.layoutMonthSchedule.addView(it)
CoroutineScope(Dispatchers.IO).launch {
val scheduleContainer = makePaddingScheduleList(item, schedules)
val hasAnySchedule = scheduleContainer.any { it != null }
if (hasAnySchedule) {
withContext(Dispatchers.Main) {
binding.layoutMonthSchedule.removeAllViews()
scheduleContainer.map { it ?: makeDefaultScheduleTextView() }
.forEach {
binding.layoutMonthSchedule.addView(it)
}
}
}
}
}

Expand Down Expand Up @@ -207,4 +223,8 @@ class MonthAdapter(val onDaySelectStateListener: OnDaySelectStateListener) : Lis

private const val MAX_VISIBLE_SCHEDULE_SIZE = 3
}

override fun getItemCount(): Int {
return currentList.size
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.drunkenboys.ckscalendar.month

import android.util.Log
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.GridLayoutManager
Expand All @@ -9,12 +10,15 @@ import com.drunkenboys.ckscalendar.databinding.ItemMonthPageBinding
import com.drunkenboys.ckscalendar.listener.OnDayClickListener
import com.drunkenboys.ckscalendar.listener.OnDaySecondClickListener
import com.drunkenboys.ckscalendar.utils.TimeUtils.parseDayWeekToDayType
import kotlinx.coroutines.*
import java.time.DayOfWeek
import java.time.LocalDate


class MonthPageAdapter : RecyclerView.Adapter<MonthPageAdapter.Holder>() {

private var timeTest = 0L

private val list = mutableListOf<CalendarSet>()

private val schedules = mutableListOf<CalendarScheduleObject>()
Expand All @@ -36,6 +40,9 @@ class MonthPageAdapter : RecyclerView.Adapter<MonthPageAdapter.Holder>() {
cachedCalendar.clear()
this.list.clear()
this.list.addAll(list)

timeTest = System.currentTimeMillis()
Log.e(this::class.simpleName, "setItems")
notifyDataSetChanged()
}

Expand Down Expand Up @@ -87,63 +94,69 @@ class MonthPageAdapter : RecyclerView.Adapter<MonthPageAdapter.Holder>() {
onDayClick: OnDayClickListener?,
onDaySecondClick: OnDaySecondClickListener?
) {
val dates = mutableListOf<CalendarDate>()
val startMonth = item.startDate.monthValue
val startDay = item.startDate.dayOfWeek
val endMonth = item.endDate.monthValue

cachedCalendar[item.id]?.let {
dates.addAll(it)
} ?: run {
(startMonth..endMonth).forEach { month ->
when (month) {
startMonth -> {
// add Start Padding
if (startDay != DayOfWeek.SUNDAY) {
dates.addAll(makePadding(startDay.ordinal))
CoroutineScope(Dispatchers.IO).launch {
val dates = mutableListOf<CalendarDate>()
val startMonth = item.startDate.monthValue
val startDay = item.startDate.dayOfWeek
val endMonth = item.endDate.monthValue

cachedCalendar[item.id]?.let {
dates.addAll(it)
} ?: run {
(startMonth..endMonth).forEach { month ->
when (month) {
startMonth -> {
// add Start Padding
if (startDay != DayOfWeek.SUNDAY) {
dates.addAll(makePadding(startDay.ordinal))
}

// add Start Dates
dates.addAll(makeDates(item.startDate, month))
}
else -> {
// add Normal Dates
dates.addAll(makeDates(item.endDate, month))
}

// add Start Dates
dates.addAll(makeDates(item.startDate, month))
}
else -> {
// add Normal Dates
dates.addAll(makeDates(item.endDate, month))
}
}
// add End Padding
val weekPadding = 6 - dates.size % weekSize
dates.addAll(makePadding(weekPadding))

// add FullSize Padding
if (dates.size < calendarFullSize) {
val fullSizePadding = calendarFullSize - dates.size - 1
dates.addAll(makePadding(fullSizePadding))
}
}
// add End Padding
val weekPadding = 6 - dates.size % weekSize
dates.addAll(makePadding(weekPadding))

// add FullSize Padding
if (dates.size < calendarFullSize) {
val fullSizePadding = calendarFullSize - dates.size - 1
dates.addAll(makePadding(fullSizePadding))
}
}

// check and set recycle data
if (lastSelectPagePosition == adapterPosition) {
monthAdapter.selectedPosition = lastSelectDayPosition
} else {
monthAdapter.selectedPosition = -1
}
// check and set recycle data
if (lastSelectPagePosition == adapterPosition) {
monthAdapter.selectedPosition = lastSelectDayPosition
} else {
monthAdapter.selectedPosition = -1
}

if (isFirstToday) {
dates.find {
it.date.monthValue == today.monthValue &&
it.date.dayOfMonth == today.dayOfMonth &&
it.dayType != DayType.PADDING
}?.let {
it.isSelected = true
isFirstToday = false
if (isFirstToday) {
dates.find {
it.date.monthValue == today.monthValue &&
it.date.dayOfMonth == today.dayOfMonth &&
it.dayType != DayType.PADDING
}?.let {
it.isSelected = true
isFirstToday = false
}
}
withContext(Dispatchers.Main){
monthAdapter.setItems(dates, schedules, calendarDesign, adapterPosition)
monthAdapter.onDateClickListener = onDayClick
monthAdapter.onDateSecondClickListener = onDaySecondClick
}
}

monthAdapter.setItems(dates, schedules, calendarDesign, adapterPosition)
monthAdapter.onDateClickListener = onDayClick
monthAdapter.onDateSecondClickListener = onDaySecondClick

Log.e("monthPage", "bind end $adapterPosition ${System.currentTimeMillis() - timeTest}")
}

private fun makeDates(date: LocalDate, month: Int): List<CalendarDate> {
Expand Down

0 comments on commit bc2b169

Please sign in to comment.