0

I am developing NewsApi app. I set a search edit text for searching through articles, but the search works only for the first time. When I write another word in edit text recyclerView still shows articles related to the previous word. Please let me know if I need to post something more.

Fragment:

class SearchNewsFragment : Fragment(R.layout.fragment_search_news) {



lateinit var viewModel: NewsViewModel
lateinit var newsAdapter: NewsAdapter

private var recyclerView: RecyclerView? = null
private var gridLayoutManager: GridLayoutManager? = null
private var sourceAdapters: SourceAdapters? = null

val TAG = "SearchNewsFragment"

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    viewModel = (activity as NewsActivity).viewModel

    setupRecyclerView()
    initViews()

    // navigate to the clicked article
    newsAdapter.setOnItemClickListener {
        val bundle = Bundle().apply {
            putSerializable("article", it)
        }

        findNavController().navigate(
            R.id.action_searchNewsFragment_to_articleFragment,
            bundle
        )

    }

    var job: Job? = null
    etSearch.addTextChangedListener { editable ->
        job?.cancel()
        job = MainScope().launch {
            delay(Constants.SEARCH_NEWS_TIME_DELAY)
            editable?.let {
                if (editable.toString().isNotEmpty()) {
                    viewModel.searchNews(editable.toString())
                }
                if (editable.toString().isEmpty()){
                    hideRecyclerView()
                    showSources()

                }
            }
        }
    }

    viewModel.searchNews.observe(viewLifecycleOwner, Observer { response ->
        when (response) {
            is Resource.Success -> {
                hideSources()
                showRecyclerView()
                hideProgressBar()
                response.data?.let { newsResponse ->
                    newsAdapter.differ.submitList(newsResponse.articles.toList())
                    val totalPages = newsResponse.totalResults / Constants.QUERY_PAGE_SIZE + 2
                    isLastPage = viewModel.searchNewsPage == totalPages
                    if (isLastPage) {
                        rvSearchNews.setPadding(0, 0, 0, 0)
                    }
                }
            }
            is Resource.Error -> {
                hideProgressBar()
                response.message?.let { message ->
                    Log.e(TAG, "An error accrued: $message")
                }
            }
            is Resource.Loading -> {
                showProgressBar()
            }
        }
    })
}

private fun hideSources(){
    recycler_view_source.visibility = View.INVISIBLE
}

private fun showSources(){
    recycler_view_source.visibility = View.VISIBLE
}
private fun hideRecyclerView(){
    rvSearchNews.visibility = View.INVISIBLE
}

private fun showRecyclerView(){
    rvSearchNews.visibility = View.VISIBLE
}

private fun hideProgressBar() {
    paginationProgressBar.visibility = View.INVISIBLE
    isLoading = false
}

private fun showProgressBar() {
    paginationProgressBar.visibility = View.VISIBLE
    isLoading = true
}

var isLoading = false
var isLastPage = false
var isScrolling = false

var scrollListener = object : RecyclerView.OnScrollListener() {
    override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
        super.onScrollStateChanged(recyclerView, newState)

        if (newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
            isScrolling = true
        }
    }

    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
        super.onScrolled(recyclerView, dx, dy)

        val layoutManager = recyclerView.layoutManager as LinearLayoutManager
        val firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition()
        val visibleItemCount = layoutManager.childCount
        val totalItemCount = layoutManager.itemCount

        val isNotLoadingAndNotLastPage = !isLoading && !isLastPage
        val isAtLastItem = firstVisibleItemPosition + visibleItemCount >= totalItemCount
        val isNotAtBeginning = firstVisibleItemPosition >= 0
        val isTotalMoreThanVisible = totalItemCount >= Constants.QUERY_PAGE_SIZE
        val shouldPaginate =
            isNotLoadingAndNotLastPage && isAtLastItem && isNotAtBeginning && isTotalMoreThanVisible && isScrolling
        if (shouldPaginate) {
            viewModel.searchNews(etSearch.text.toString())
            isScrolling = false
        }    
    }
}

private fun setupRecyclerView() {
    newsAdapter = NewsAdapter()
    rvSearchNews.apply {
        adapter = newsAdapter
        layoutManager = LinearLayoutManager(activity)
        addOnScrollListener(this@SearchNewsFragment.scrollListener)
    }
}

private fun initViews() {
    recyclerView = requireView().findViewById(R.id.recycler_view_source)
    gridLayoutManager =
        GridLayoutManager(
            requireContext().applicationContext,
            2,
            LinearLayoutManager.VERTICAL,
            false
        )
    recyclerView?.layoutManager = gridLayoutManager
    recyclerView?.setHasFixedSize(true)
    sourceAdapters = SourceAdapters(requireContext().applicationContext, listOf())
    viewModel.getSources("us")
    viewModel.sourcesPage.observe(viewLifecycleOwner){
        sourceAdapters?.submitList(it)
    }
    sourceAdapters?.onSourceClick = {
        val action = SearchNewsFragmentDirections.actionSearchNewsFragmentToBreakingNewsFragment(null, it)
        findNavController().navigate(action)
    }
    recyclerView?.adapter = sourceAdapters
}

Here is my sAdapter:

class NewsAdapter : RecyclerView.Adapter<NewsAdapter.ArticleViewHolder>() {

inner class ArticleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)

private val differCallback = object : DiffUtil.ItemCallback<Article>() {
    override fun areItemsTheSame(oldItem: Article, newItem: Article): Boolean {
        return oldItem.url == newItem.url
    }

    override fun areContentsTheSame(oldItem: Article, newItem: Article): Boolean {
        return oldItem == newItem
    }
}

val differ = AsyncListDiffer(this, differCallback)

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArticleViewHolder {
    return ArticleViewHolder(
        LayoutInflater.from(parent.context).inflate(
            R.layout.item_article_preview,
            parent,
            false
        )
    )
}

override fun onBindViewHolder(holder: ArticleViewHolder, position: Int) {
    val article = differ.currentList[position]
    holder.itemView.apply {
        Glide.with(this).load(article.urlToImage).into(article_imageView)
        source.text = article.source?.name
        headline.text = article.title
        setOnClickListener{
            onItemClickListener?.let {
                it(article)
            }
        }
    }
}

override fun getItemCount(): Int {
    return differ.currentList.size
}

fun setOnItemClickListener(listen: (Article) -> Unit){
    onItemClickListener = listen
}

private var onItemClickListener: ((Article) -> Unit)? = null

}

Fary
  • 43
  • 5
  • You need to clear previous data from RecyclerView before new search – ahjo4321hsotuhsa Sep 19 '22 at 05:39
  • Can you explain what methods and where to use? – Fary Sep 19 '22 at 07:01
  • You can have a method like this to clear the previous data before updating Recycler with new data public fun updateData(val newList:ArrayList) { currentList.clear(); currentList.addAll(newList); notifyDataSetChanged(); } – ahjo4321hsotuhsa Sep 19 '22 at 07:07
  • If you still have that problem, i had that too and managed to solve that in [here](https://stackoverflow.com/questions/74329510/retrofit-responses-keep-the-old-data-and-add-the-new-one-to-that-for-edittext-se) – Mert Nov 06 '22 at 13:36

1 Answers1

0

You can have a method like this to clear the previous data before updating Recycler with new data

public fun updateData(val newList:ArrayList<Data>) {
currentList.clear();
currentList.addAll(newList);
notifyDataSetChanged();
}