Reputation: 37
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
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