【发布时间】:2021-02-16 14:03:05
【问题描述】:
我现在正在编码的片段应该为用户提供他的膳食计划时间表的日历概览。因此,通过日期选择器,他可以选择一个时间段,程序将向用户显示他为所选工作日选择了哪些食谱。 因此,我构建了一个嵌套的 RecyclerView,其中工作日作为父层,相应的食谱作为子层。工作日层的数据类如下所示:
data class Weekday (
val weekday : String,
val listWithRecipes : List<Recipe>?
)
Recipe 实体的类如下所示:
@Entity(tableName = "Recipe")
@Parcelize
data class Recipe(
@PrimaryKey var recipeName : String,
var description : String?,
var serving : Int,
var preparationTime : Int?
) : Parcelable
顶部 Recycler 视图的适配器如下所示:
class MealPlanAdapter(private var mealplan: List<Weekday>) :
RecyclerView.Adapter<MealPlanAdapter.MealPlanViewHolder>(), RecipeAdapter.OnItemClickListener {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MealPlanViewHolder {
return MealPlanViewHolder(
DailyMealplanItemBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun getItemCount() = mealplan.size
override fun onBindViewHolder(holder: MealPlanViewHolder, position: Int) {
val weekday = mealplan[position]
val recipeAdapter = RecipeAdapter(this)
recipeAdapter.submitList(weekday?.listWithRecipes)
holder.dayOfWeek.text = weekday.weekday
val recipeLayoutManager = LinearLayoutManager(holder.recyclerView.context,RecyclerView.VERTICAL, false)
recipeLayoutManager.initialPrefetchItemCount = 4
holder.recyclerView.apply{
layoutManager = recipeLayoutManager
adapter = recipeAdapter
}
}
fun setSchedule(mealplan : List <Weekday>){
this.mealplan = mealplan
notifyDataSetChanged()
}
inner class MealPlanViewHolder(val binding: DailyMealplanItemBinding) :
RecyclerView.ViewHolder(binding.root) {
val recyclerView: RecyclerView = binding.rvRecyclerView
val dayOfWeek: TextView = binding.tvDayOfWeek
}
override fun onItemClick(recipe: Recipe) {
TODO("Not yet implemented")
}
}
每当用户更改时间段时,都会在片段中调用适配器中的 setScheduled() 方法。
materialDatePickerStartDate.addOnPositiveButtonClickListener(
MaterialPickerOnPositiveButtonClickListener<Any?> { selection ->
_binding.viewmodel!!.startDateInUTCFormat = selection as Long
_binding.tvStartDate.setText(materialDatePickerStartDate.headerText)
adapter.setSchedule(
_binding.viewmodel!!.returnListWithWeekDaysAndCorrespondingRecipes(
_binding.viewmodel!!.startDateInUTCFormat,
_binding.viewmodel!!.endDateInUTCFormat
)
)
}
)
视图模型如下所示:
@HiltViewModel
class MealplanViewModel @Inject constructor(
val mealPlanRepository: MealPlanRepository
) : ViewModel() {
private lateinit var _binding: FragmentMealPlanBinding
var startDateInUTCFormat: Long = System.currentTimeMillis()
var endDateInUTCFormat: Long = System.currentTimeMillis()
fun returnListWithWeekDaysAndCorrespondingRecipes(
startDate: Long,
endDate: Long
): ArrayList<Weekday> {
var startDate = Date(startDateInUTCFormat)
var endDate = Date(endDateInUTCFormat)
var startDateCalendar = dateToCalendar(startDate)
var endDateCalendar = dateToCalendar(endDate)
val calendarDays = createListWithCalendarDates(startDateCalendar, endDateCalendar)
return createListWithWeekDaysAndCorrespondingRecipes(calendarDays)
}
fun dateToCalendar(date: Date): Calendar {
var calInstance = Calendar.getInstance()
calInstance.setTime(date)
return calInstance
}
fun createListWithCalendarDates(
startDateCalendar: Calendar,
endDateCalendar: Calendar
): ArrayList<Calendar> {
var listWithCalendarDates = arrayListOf<Calendar>()
while (startDateCalendar <= endDateCalendar) {
listWithCalendarDates.add(startDateCalendar.clone() as Calendar)
startDateCalendar.add(Calendar.DATE, 1)
}
return listWithCalendarDates
}
fun createListWithWeekDaysAndCorrespondingRecipes(calendarDays: ArrayList<Calendar>): ArrayList<Weekday> {
var dayOfWeekAsString: String
var listWithDaysOfWeeksAndRecipes = arrayListOf<Weekday>()
var flattenedListWithRecipes: List<Recipe>?
for (i in 0 until calendarDays.size) {
var dayOfWeekAsInt = calendarDays[i].get(Calendar.DAY_OF_WEEK)
dayOfWeekAsString = when (dayOfWeekAsInt) {
1 -> "Sunday"
2 -> "Monday"
3 -> "Tuesday"
4 -> "Wednesday"
5 -> "Thursday"
6 -> "Friday"
else -> "Saturday"
}
var calendarDateInString =
transformCalendarDateIntoRequiredStringFormat(calendarDays[i])
var listWithDateAndCorrespondingRecipes: List<MealplanScheduleWithRecipes> =
listOf()
var liveDatalistWithDateAndCorrespondingRecipes =
mealPlanRepository.getMealplanScheduleWithRecipes(calendarDateInString)
liveDatalistWithDateAndCorrespondingRecipes.observeForever() { list ->
listWithDateAndCorrespondingRecipes = list
var listWithRecipes = listWithDateAndCorrespondingRecipes?.map { it.recipes }
flattenedListWithRecipes = listWithRecipes?.flatten()
var wochentag = dayOfWeekAsString
listWithDaysOfWeeksAndRecipes.add(Weekday(dayOfWeekAsString, flattenedListWithRecipes))
}
}
return listWithDaysOfWeeksAndRecipes
}
fun transformCalendarDateIntoRequiredStringFormat(calendarDate: Calendar): String {
var year = calendarDate.get(Calendar.YEAR)
var month = transformCalendarMonthFormatToCorrectMonth(calendarDate)
var day = calendarDate.get(Calendar.DAY_OF_MONTH)
return "$day" + "$month" + "$year"
}
fun transformCalendarMonthFormatToCorrectMonth(calendarDate: Calendar): String {
var monthCalendarFormat = calendarDate.get(Calendar.MONTH)
var monthCorrectFormat = when (monthCalendarFormat) {
0 -> "1"
1 -> "2"
2 -> "3"
3 -> "4"
4 -> "5"
5 -> "6"
6 -> "7"
7 -> "8"
8 -> "9"
9 -> "10"
10 -> "11"
else -> "12"
}
return monthCorrectFormat
}
fun datesAreReasonable(startDate: Long, endDate: Long): Boolean {
return (startDate <= endDate)
}
}
我的问题是传递给 RecyclerView 适配器的列表由 Weekday 对象组成,这些对象由工作日的名称和相应的食谱组成(请参阅顶部的数据类“weekday”)。 在视图模型中的“createListWithWeekDaysAndCorrespondingRecipes”方法中,我在一个 for 循环中创建了这个列表,该循环获取给定日期及其相应食谱之间的所有工作日。但是,食谱是通过 Room 数据库查询异步获取的 LiveData,而工作日的名称是在主线程中同步派生的。然而,最后当我创建 Weekday 对象时 (请参阅 for 循环末尾的 listWithDaysOfWeeksAndRecipes.add(Weekday(dayOfWeekAsString, flattenedListWithRecipes) )我同时需要它们。我还没有找到一种方法如何成功地协调它。目前添加的逻辑列表中的对象位于异步“observeForever”块中。 见这里:
liveDatalistWithDateAndCorrespondingRecipes.observeForever() { list ->
listWithDateAndCorrespondingRecipes = list
var listWithRecipes = listWithDateAndCorrespondingRecipes?.map { it.recipes }
flattenedListWithRecipes = listWithRecipes?.flatten()
var wochentag = dayOfWeekAsString
listWithDaysOfWeeksAndRecipes.add(Weekday(dayOfWeekAsString, flattenedListWithRecipes))
}
这会产生错误的结果,可能是因为主线程和观察者线程之间的协调不起作用。 但是,如果我采用从观察者块中添加的逻辑,则由于查询的异步特性,带有配方的列表将给我 null。
我知道我对问题的描述非常糟糕。也许还有人掌握了它并可以提供帮助?
【问题讨论】:
标签: android kotlin android-recyclerview android-room android-livedata