You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin中如何用Retrofit实现RecyclerView加载更多且保留旧数据?

Fixing Infinite Scroll Data Replacement Issue in Kotlin + Retrofit

Hey there! I see exactly what's going wrong with your infinite scroll setup—let's get that fixed so your new movie items stack after the old ones instead of replacing them.

The Root Problem

Right now, every time you call getPopularMovies() for a new page, you're creating a brand new MovieAdapter instance and passing only the latest page's results to it. Then you reassign this new adapter to your RecyclerView, which wipes out all the old data and replaces it with the new page. That's why your old items disappear!

Step-by-Step Solution

1. Initialize Your Adapter Once

First, set up your MovieAdapter as a member variable in your Fragment, and initialize it once when the view is created (instead of every API call). This keeps your adapter instance consistent:

private lateinit var moviesAdapter: MovieAdapter

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    
    // Initialize adapter with an empty list first
    moviesAdapter = MovieAdapter(movies = emptyList())
    moviesList.adapter = moviesAdapter
    
    // Load the first page to kick things off
    getPopularMovies(1)
}

2. Add a Data Append Method to Your Adapter

Modify your MovieAdapter to include a method that adds new movies to the existing list, instead of replacing it. This lets you update the data without creating a new adapter:

class MovieAdapter(private var movies: List<Movie>) : RecyclerView.Adapter<MovieAdapter.MovieViewHolder>() {
    // ... Keep your existing ViewHolder, onCreateViewHolder, and onBindViewHolder code ...

    // Method to append new movies to the list
    fun addNewMovies(newMovies: List<Movie>) {
        // Combine existing list with new data
        val updatedList = movies + newMovies
        movies = updatedList
        
        // Notify RecyclerView only about the new items (more efficient than notifyDataSetChanged())
        notifyItemRangeInserted(
            startPosition = movies.size - newMovies.size,
            itemCount = newMovies.size
        )
    }

    // Optional: Add a method to replace the list (for the first page)
    fun setInitialMovies(initialMovies: List<Movie>) {
        movies = initialMovies
        notifyDataSetChanged()
    }
}

3. Update Your API Call to Append Data

Now adjust your getPopularMovies() function to either set the initial data (for page 1) or append new data (for subsequent pages), instead of creating a new adapter every time:

private fun getPopularMovies(page: Int){ 
    val repository = MoviesRepositoryProvider.provideMovieRepository() 
    repository.getPopularMovies(page) 
        .observeOn(AndroidSchedulers.mainThread()) 
        .subscribeOn(Schedulers.io()) 
        .subscribe ({ result -> 
            if (page == 1) {
                // First page: Replace the empty list with initial data
                moviesAdapter.setInitialMovies(result.results)
            } else {
                // Subsequent pages: Append new movies to the existing list
                moviesAdapter.addNewMovies(result.results)
            }
        }, { error -> 
            error.printStackTrace() 
        }) 
}

Bonus Tip: Prevent Duplicate Requests

To avoid accidentally loading the same page multiple times (e.g., if the user scrolls quickly), add a boolean flag to track if a request is already in progress:

private var isLoading = false

private fun getPopularMovies(page: Int){ 
    if (isLoading) return // Exit if a request is already running
    
    isLoading = true
    val repository = MoviesRepositoryProvider.provideMovieRepository() 
    repository.getPopularMovies(page) 
        .observeOn(AndroidSchedulers.mainThread()) 
        .subscribeOn(Schedulers.io()) 
        .subscribe ({ result -> 
            // ... Your existing data update code ...
            isLoading = false // Reset flag after successful load
        }, { error -> 
            error.printStackTrace() 
            isLoading = false // Reset flag even if request fails
        }) 
}

That should do it! Now when you scroll to the bottom, new movie items will be added to the end of your list instead of replacing the old ones.

内容的提问来源于stack exchange,提问作者Endyrmion

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:01:17