Kotlin recyclerview 分页重启(Pagination)

Posted

技术标签:

【中文标题】Kotlin recyclerview 分页重启(Pagination)【英文标题】:Kotlin recyclerview pagination restarts (Pagination) 【发布时间】:2022-01-15 09:49:35 【问题描述】:

我目前正在开发一个基于 TMDB 的 Kotlin 应用程序,试图实现分页我实现了它,但是当添加更多项目时,recyclerview “重新启动”(将我发送到列表顶部)。

我认为问题可能是我的适配器或我设置 recylerview 的方式。

有什么建议吗?

我的适配器

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)
            
        

    

实施

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())
                        
                    
                
            )

        
    




我尝试添加另一种方法来仅将项目添加到列表中,但这样做视图不会刷新

【问题讨论】:

你需要实现NotifyDataChanged:For better explanation 我尝试了你的建议,但是,recyclerview 更新的唯一方法是向上滚动 【参考方案1】:

问题是您每次收到一些新数据时都在初始化适配器。 尝试在 SearchMovieAdapter 类中添加 insertMovie 函数,该函数添加单个项目并通知其插入:

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

然后在每次收到新对象时使用它来更新您的适配器:

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])
                    
                
            

【讨论】:

不只是重新创建适配器,还分配一个新的LayoutManager - 你基本上每次都清除整个RecyclerView,这就是它重置的原因

以上是关于Kotlin recyclerview 分页重启(Pagination)的主要内容,如果未能解决你的问题,请参考以下文章

kotlin Recycler查看分页

提供Kotlin阵列的补偿 .take(n:Int)。这是分页的好方法吗?

Kotlin、RecyclerView、ViewBinding

Android Studio(Kotlin)之RecyclerView

Recyclerview没有显示kotlin [重复]

Kotlin 简单的RecyclerView