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
}