0

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())
}
Esteban
  • 69
  • 1
  • 11

1 Answers1

1

too late but it is because of "searchRecipesResponse". You have to set it to "null" and reset searchRecipesPage to 1 for each new search in etSearch.setOnKeyListener().

NimaAzhd
  • 162
  • 3
  • 15