Retrofit+RecyclerView数据加载:展示指定条数及实现加载更多
Hey there! Let's walk through this step by step—it's straightforward once you break it down:
1. Set Up Retrofit & Define Your API Interface
First, make sure you have Retrofit and a JSON converter (like Gson Converter) added to your build config. Then create an API interface that accepts pagination parameters to fetch exactly 10 records. For example:interface ApiService { @GET("your-data-endpoint") suspend fun getRecords( @Query("page") page: Int = 1, @Query("limit") limit: Int = 10 ): Response<RecordResponse> }We default to
page=1andlimit=10here to grab the first batch of records.2. Create Data Models
Map the API's JSON response to a data class (Kotlin) or Java Bean. Keep it aligned with the structure your API returns:data class RecordResponse(val data: List<Record>) data class Record(val id: Int, val title: String, val description: String)3. Configure RecyclerView & Adapter
Build a RecyclerView.Adapter and ViewHolder to render your records. The adapter will hold a mutable list ofRecordobjects:class RecordAdapter(private val records: MutableList<Record>) : RecyclerView.Adapter<RecordAdapter.RecordViewHolder>() { inner class RecordViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { fun bind(record: Record) { itemView.tv_title.text = record.title itemView.tv_description.text = record.description } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecordViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.item_record, parent, false) return RecordViewHolder(view) } override fun onBindViewHolder(holder: RecordViewHolder, position: Int) { holder.bind(records[position]) } override fun getItemCount(): Int = records.size }4. Fetch & Display Data
In your Activity/Fragment, initialize Retrofit, call the API, and update the RecyclerView once you get the data. Using Kotlin Coroutines for clean async calls:class MainActivity : AppCompatActivity() { private lateinit var adapter: RecordAdapter private val records = mutableListOf<Record>() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Set up RecyclerView recyclerView.layoutManager = LinearLayoutManager(this) adapter = RecordAdapter(records) recyclerView.adapter = adapter // Fetch first 10 records lifecycleScope.launch { fetchInitialRecords() } } private suspend fun fetchInitialRecords() { val apiService = Retrofit.Builder() .baseUrl("https://your-api-base-url.com/") .addConverterFactory(GsonConverterFactory.create()) .build() .create(ApiService::class.java) try { val response = apiService.getRecords() if (response.isSuccessful) { response.body()?.data?.let { records.clear() records.addAll(it) adapter.notifyDataSetChanged() } } } catch (e: Exception) { // Handle error (show toast, log, etc.) e.printStackTrace() } } }
Great question—adding a load more button is a common pattern, and here's how to implement it smoothly:
1. Confirm API Pagination Support
You probably already havepageandlimitparameters set up (since you fetched 20 records). We’ll increment the page number each time we load more, keepinglimit=10to grab the next batch.2. Modify Adapter to Include Load More View
Add a new view type for the load more button, and update the adapter to handle it:class RecordAdapter( private val records: MutableList<Record>, private val onLoadMoreClicked: () -> Unit ) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { private val VIEW_TYPE_RECORD = 0 private val VIEW_TYPE_LOAD_MORE = 1 private var isLoading = false fun setLoadingState(loading: Boolean) { isLoading = loading notifyItemChanged(records.size) } inner class RecordViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { fun bind(record: Record) { itemView.tv_title.text = record.title itemView.tv_description.text = record.description } } inner class LoadMoreViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { init { itemView.btn_load_more.setOnClickListener { if (!isLoading) onLoadMoreClicked.invoke() } } } override fun getItemViewType(position: Int): Int { return if (position == records.size) VIEW_TYPE_LOAD_MORE else VIEW_TYPE_RECORD } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { return if (viewType == VIEW_TYPE_RECORD) { val view = LayoutInflater.from(parent.context).inflate(R.layout.item_record, parent, false) RecordViewHolder(view) } else { val view = LayoutInflater.from(parent.context).inflate(R.layout.item_load_more, parent, false) LoadMoreViewHolder(view) } } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { if (holder is RecordViewHolder) { holder.bind(records[position]) } else if (holder is LoadMoreViewHolder) { // Update button text based on loading state holder.itemView.btn_load_more.text = if (isLoading) "Loading..." else "Load More" holder.itemView.btn_load_more.isEnabled = !isLoading } } override fun getItemCount(): Int = records.size + 1 // +1 for the load more item }Note: Create a layout
item_load_more.xmlwith a Button (or ProgressBar + Button) for the load more action.3. Handle Load More in Activity/Fragment
Track the current page number, and when the button is clicked, fetch the next page and append the data:class MainActivity : AppCompatActivity() { private lateinit var adapter: RecordAdapter private val records = mutableListOf<Record>() private var currentPage = 3 // Since you already have 20 records (pages 1 + 2, 10 each) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Assume records already contain 20 items here recyclerView.layoutManager = LinearLayoutManager(this) adapter = RecordAdapter(records) { lifecycleScope.launch { loadMoreRecords() } } recyclerView.adapter = adapter } private suspend fun loadMoreRecords() { adapter.setLoadingState(true) val apiService = Retrofit.Builder() .baseUrl("https://your-api-base-url.com/") .addConverterFactory(GsonConverterFactory.create()) .build() .create(ApiService::class.java) try { val response = apiService.getRecords(currentPage, 10) if (response.isSuccessful) { response.body()?.data?.let { newRecords -> val startPosition = records.size records.addAll(newRecords) adapter.notifyItemRangeInserted(startPosition, newRecords.size) currentPage++ // If no more records, hide the load more item or update text if (newRecords.isEmpty()) { // Example: adapter.removeLoadMoreItem() (add this method to adapter if needed) } } } } catch (e: Exception) { e.printStackTrace() } finally { adapter.setLoadingState(false) } } }4. Key Considerations
- Use the
isLoadingflag to prevent duplicate requests while fetching data. - Handle edge cases: if there are no more records, hide the load more button or change its text to "No More Records".
- Use
notifyItemRangeInsertedinstead ofnotifyDataSetChangedfor better RecyclerView performance.
- Use the
内容的提问来源于stack exchange,提问作者jeetdeveloper

