Alexis Chavarría
Alexis Chavarría

Reputation: 37

Kotlin recyclerview pagination restarts (Pagination)

I am currently developing a Kotlin app based on the TMDB, trying to implement pagination I achieved it but when more items are added, the recyclerview "restarts" (sends me to the top of the list).

I think the problem maybe is my adapter or the way I am setting the recylerview.

Any suggestion?

My adapter

class SearchMovieAdapter(val movieList: ArrayList<MovieData>, val listener: ClickListener) :
    RecyclerView.Adapter<SearchMovieAdapter.SearchViewHolder>() {


    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchViewHolder {
        val view: LayoutInflater = LayoutInflater.from(parent.context)
        return SearchViewHolder(view.inflate(R.layout.search_item, parent, false))
    }

    override fun onBindViewHolder(holder: SearchViewHolder, position: Int) {
        return holder.bindInfo(movieList[position])
    }

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



    inner class SearchViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var itemImage: ImageView = itemView.findViewById(R.id.imageFound)
        fun bindInfo(movie: MovieData) {
            itemView.setOnClickListener{
                //listener.OnItemClick(movie.id.toString(), image.context)
                listener.OnItemClick(movie, itemImage.context)
            }
            // title.text = movie.title
            if (movie.poster_path != null) {

                Picasso.get().load("https://image.tmdb.org/t/p/w500${movie.poster_path}")
                    .into(itemImage)
            }
        }

    }

Implementation

class SearchPage :
    ClickListener,
    AppCompatActivity() {
    private lateinit var editableText: EditText
    private lateinit var listOfSearchedMovies: RecyclerView
    var searchedQuery: ArrayList<MovieData> = ArrayList()
    var queryText: String = ""
    var indexPage = 1
    val indexLimit = 3
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_search_page)

        editableText = findViewById(R.id.buscarPeli)

        //When user click enter key on keyboard
        editableText.setOnKeyListener(View.OnKeyListener { _, keyCode, event ->
            if (keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_DOWN) {
                //Perform Code
                val query: String = editableText.text.toString()
                queryText = query
                
                //Search movies data
                if (searchedQuery.isEmpty()) {
                    setSearchedTitle(query, indexPage.toString())
                }

                editableText.text.clear()
                hideKeyboard()
                Toast.makeText(this, query, Toast.LENGTH_SHORT).show()
                return@OnKeyListener true
            }
            false
        })


    }

    private fun hideKeyboard() {
        val view = this.currentFocus
        if (view != null) {
            val hide = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
            hide.hideSoftInputFromWindow(view.windowToken, 0)
        }
        window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN)
    }

    private fun setSearchedTitle(query: String, index: String) {

        val retrofitBuilder = Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())
            .baseUrl(com.example.recyclerview.BASE_URL)
            .build()
            .create(API_interface::class.java)
        val retrofitData = retrofitBuilder.searchMovies(query, index)
        retrofitData.enqueue(object : Callback<MoviesResponse?> {
            override fun onResponse(
                call: Call<MoviesResponse?>,
                response: Response<MoviesResponse?>
            ) {
                if (response.isSuccessful) {
                    //searchedQuery.clear()
                    val totalResults = response.body()!!.results.size

                    for (i in 0 until totalResults)
                        searchedQuery.add(response.body()!!.results[i])
                }
                //Log.d("Respuesta", "Lista respuesta ${searchedQuery.size} ")
                //index=index+1
                setMoviesRecyclerView(searchedQuery)
            }

            override fun onFailure(call: Call<MoviesResponse?>, t: Throwable) {
                Toast.makeText(this@SearchPage, "${t.message}", Toast.LENGTH_SHORT).show()
            }
        })
    }


    private fun setMoviesRecyclerView(searchedQuery: ArrayList<MovieData>) {
        val loading: ProgressBar = findViewById(R.id.movieResultsLoading)
        listOfSearchedMovies = findViewById(R.id.searcheMovies)
        listOfSearchedMovies.apply {
            val layoutManager: RecyclerView.LayoutManager =
                GridLayoutManager(listOfSearchedMovies.context, 2)
            listOfSearchedMovies.layoutManager = layoutManager
            adapter = SearchMovieAdapter(searchedQuery, this@SearchPage)
            listOfSearchedMovies.addOnScrollListener(object : RecyclerView.OnScrollListener() {
                override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                    super.onScrolled(recyclerView, dx, dy)
                    if (!recyclerView.canScrollVertically(1)) {
                        indexPage++
                        if (indexPage > indexLimit) {
                            Toast.makeText(
                                recyclerView.context,
                                "¡That's all!",
                                Toast.LENGTH_LONG
                            ).show()
                        } else {
                            setSearchedTitle(queryText, indexPage.toString())
                        }
                    }
                }
            })

        }
    }



}

I tried adding another method to only add items to the list, but doing that the view doesn't refresh

Upvotes: 0

Views: 838

Answers (1)

lpizzinidev
lpizzinidev

Reputation: 13274

The problem is that you are initializing the adapter every time you receive some new data.
Try to add a insertMovie function in the SearchMovieAdapter class, which add a single item and notify its insertion:

fun insertMovie(newMovie: MovieData) {
    this.movieList.add(newMovie)
    notifyItemInserted(movieList.size - 1)
}

Then use it to update your adapter every time you receive a new object:

retrofitData.enqueue(object : Callback<MoviesResponse?> {
            override fun onResponse(
                call: Call<MoviesResponse?>,
                response: Response<MoviesResponse?>
            ) {
                if (response.isSuccessful) {
                    //searchedQuery.clear()
                    val totalResults = response.body()!!.results.size

                    for (i in 0 until totalResults) {
                        adapter.insertMovie(response.body()!!.results[i])
                    }
                }
            }

Upvotes: 1

Related Questions