Reputation: 117
This is what happened
I just realize you can't see the touch event
So the first one i touched misc, the second one i touched pasta
I don't think this is the correct behavior, right? Should i save the position when i leave, and scroll the list in onresume?
This is my adapter
class CategoryListAdapter(private val onClickListener: OnClickListener) :
ListAdapter<Category, CategoryListAdapter.CategoryViewHolder>(DiffCallback) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CategoryViewHolder =
CategoryViewHolder(
ItemListVerticalBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
override fun onBindViewHolder(holder: CategoryViewHolder, position: Int) {
val category = getItem(position)
holder.bindCategory(category)
holder.itemView.setOnClickListener {
onClickListener.onClick(category)
}
}
companion object DiffCallback : DiffUtil.ItemCallback<Category>() {
override fun areItemsTheSame(oldItem: Category, newItem: Category): Boolean =
oldItem == newItem
override fun areContentsTheSame(oldItem: Category, newItem: Category): Boolean =
oldItem.id == newItem.id
&& oldItem.name == newItem.name
&& oldItem.lastAccessed == newItem.lastAccessed
&& oldItem.thumbnailUrl == newItem.thumbnailUrl
}
inner class CategoryViewHolder(private var binding: ItemListVerticalBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bindCategory(category: Category) {
binding.itemImageView.load(category.thumbnailUrl)
binding.itemTextView.text = category.name
}
}
class OnClickListener(val clickListener: (category: Category) -> Unit) {
fun onClick(category: Category) = clickListener(category)
}
}
This is my populating method in the fragment
private fun setTheCategories(){
lifecycleScope.launchWhenStarted {
val adapter = CategoryListAdapter(
CategoryListAdapter.OnClickListener{
lifecycleScope.launchWhenStarted {
viewModel.displayCategoryMeals(it)
}
}
)
binding.categoryRecyclerView.layoutManager = LinearLayoutManager(requireContext())
binding.categoryRecyclerView.adapter = adapter
viewModel.categories.collect { resource ->
when (resource.status) {
Resource.Status.LOADING -> {
Log.v("CATEGORY", "LOADING")
}
Resource.Status.SUCCESS -> {
Log.v("CATEGORY", "SUCCESS")
val categories = resource.data!!
adapter.submitList(categories)
}
Resource.Status.ERROR -> {
val categories = resource.data!!
if(categories[0].name.isNotEmpty()){
adapter.submitList(categories)
}
Log.v("CATEGORY", "ERROR")
}
}
}
}
}
This is how i navigate to next fragment
private fun goToCategoryMeals(){
lifecycleScope.launchWhenStarted {
viewModel.category.collect {
if(it != null) {
[email protected]().navigate(
CategoryFragmentDirections.actionCategoryFragmentToCategoryMealsFragment(
categoryName = it.name,
savedDate = it.lastAccessed
)
)
viewModel.navigatedToCategoryMeals()
}
}
}
}
This is a part of my viewmodel
init {
getAllCategories(sharedPrefRepo.getString(AppConstants.CURR_DATE_CAT))
}
private fun getAllCategories(savedDate: String) {
viewModelScope.launch {
repo
.getCategories(savedDate)
.collect {
_categories.value = it
if (it.status == Resource.Status.SUCCESS && currDate != savedDate) {
sharedPrefRepo.putString(AppConstants.CURR_DATE_CAT, currDate)
}
}
}
}
This is a part of my repo
override suspend fun getCategories(savedDate: String): Flow<Resource<List<Category>>> =
flow {
emit(Resource.loading())
if (currDate!=savedDate){
try{
val netCategories = networkTransaction.getCategories()
dbTransaction.upsertMiniCategories(netCategories.mapToDbCategories())
}
catch (e: Exception){
if (e is HttpException){
try {
dbTransaction.getAllCategories().collect {
emit(
Resource.error(
"Something is wrong when connecting to network\n" +
"Using the old data inside local storage",
it.mapToCategories()
)
)
}
} catch (e2: IOException) {
emit(Resource.error(e2.localizedMessage!!, listOf(Category())))
}
} else {
emit(Resource.error(e.localizedMessage!!, listOf(Category())))
}
}
}
try {
dbTransaction.getAllCategories().collect {
emit(Resource.success(it.mapToCategories()))
}
}
catch (e: IOException){
emit(Resource.error(e.localizedMessage!!, listOf(Category())))
}
}.flowOn(ioDispatcher)
This is a part of my Dao
@Query("select * from DbCategory")
abstract fun getAllCategories(): Flow<List<DbCategory>>
Part of my db interface impl
override suspend fun getAllCategories(): Flow<List<DbCategory>> =
dbCategoryDao.getAllCategories().distinctUntilChanged()
EDIT 1
fragment_category.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/category_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
Upvotes: 0
Views: 612
Reputation: 183
You can solve this by using "StateRestorationPolicy" , recyclerview:1.2.0-alpha02 release StateRestorationPolicy has been introduced. It could be a better approach to the given problem.
Also, @rubén-viguera shared more details in the answer below. https://stackoverflow.com/a/61609823/892500
Upvotes: 2