I have made an app that uses an API to make a request and then shows the results in a RecyclerView. I was following a tutorial and in it they used a differCallback and a liveData so the lists updates and such. However whenever the user makes a second search, the recyclerView should only show the new results but the previous results don't dissapear and the new results just appear below the previous search.
I have debugged it for quite some time now but I don't seem to understand where the list is made and where sure it be updated (or in this case cleared). I tried using .clear() for the diff (Asynclistdiffer), creating a new list in the onBindViewHolder and then clearing that list every time the "search" is called but without any luck. As im still a beginner I don't have a clue on where or what is happening, all your helo will be greatly appreciated
this is my adapter:
class RecipePreviewAdapter : RecyclerView.Adapter<RecipePreviewAdapter.RecipePreviewViewHolder>() {
inner class RecipePreviewViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
private val differCallback = object : DiffUtil.ItemCallback<Recipe>() {
override fun areItemsTheSame(oldItem: Recipe, newItem: Recipe): Boolean {
return oldItem.sourceUrl == newItem.sourceUrl
}
override fun areContentsTheSame(oldItem: Recipe, newItem: Recipe): Boolean {
return oldItem == newItem
}
}
val differ = AsyncListDiffer(this, differCallback)
lateinit var recipeList: MutableList<Recipe>
var isRecipeListInitialized = false
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecipePreviewViewHolder {
return RecipePreviewViewHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.item_recipe_preview,
parent,
false
)
)
}
override fun onBindViewHolder(holder: RecipePreviewViewHolder, position: Int) {
recipeList = differ.currentList.toMutableList()
isRecipeListInitialized = true
// Log.d(TAG, recipeList.toString())
val recipe = recipeList[position]
holder.itemView.apply {
Glide.with(this).load(recipe.image).into(ivRecipeImagePreview)
tvRecipeTitlePreview.text = recipe.title
tvTimeToMakeTVPreview.text = "${recipe.readyInMinutes} minutes"
tvSummaryPreview.text = Jsoup.parse(recipe.summary).text()
setOnClickListener {
onItemClickListener?.let { it(recipe) }
}
}
}
override fun getItemCount(): Int {
return differ.currentList.size
}
And this is where I call it:
class SearchRecipeFragment : Fragment(R.layout.fragment_search_recipe) {
lateinit var viewModel: RecipeViewModel
lateinit var recipeAdapter: RecipePreviewAdapter
val TAG = "SearchRecipeFragment"
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel = (activity as RecipesActivity).viewModel
setupRecyclerView()
recipeAdapter.setOnItemClickListener {
val bundle = Bundle().apply {
putSerializable("recipe", it)
}
findNavController().navigate(
R.id.action_searchRecipeFragment_to_recipeFragment,
bundle
)
}
etSearch.setOnKeyListener(View.OnKeyListener { _, keyCode, event ->
if (keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_DOWN) {
if (etSearch.text.toString().isNotEmpty()) {
viewModel.searchRecipe(etSearch.text.toString())
}
return@OnKeyListener true
}
false
})
viewModel.searchRecipeLiveData.observe(viewLifecycleOwner, Observer { response ->
when (response) {
is Resource.Success -> {
hideProgressBar()
response.data?.let { recipeResponse ->
recipeAdapter.differ.submitList(recipeResponse.results.toList())
}
}
is Resource.Error -> {
hideProgressBar()
response.message?.let { message ->
Log.e(TAG, "An error occurred: $message")
Toast.makeText(activity, "An error occurred: $message", Toast.LENGTH_LONG)
.show()
}
}
is Resource.Loading -> {
showProgressBar()
}
}
})
}
Ans this is the part of the ViewModel that I'm not really sure what it does
private fun handleSearchRecipeResponse(response: Response<SearchRecipeResponse>): Resource<SearchRecipeResponse> {
if (response.isSuccessful) {
response.body()?.let { resultResponse ->
searchRecipesPage++
if (searchRecipesResponse == null) {
searchRecipesResponse = resultResponse
} else {
val oldRecipes = searchRecipesResponse?.results
val newRecipes = resultResponse.results
oldRecipes?.addAll(newRecipes)
}
return Resource.Success(searchRecipesResponse ?: resultResponse)
}
}
return Resource.Error(response.message())
}