------------------------- | PullToRefreshScreen | ------------------------- | ↓ Pull down to refresh | |-----------------------| | Item 1 | | Item 2 | | Item 3 | | Item 4 | | Item 5 | -------------------------
Pull-to-refresh in Android Kotlin - Mini App: Build & Ship
import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.LinearLayoutManager class PullToRefreshScreen : AppCompatActivity() { private lateinit var swipeRefreshLayout: SwipeRefreshLayout private lateinit var recyclerView: RecyclerView private val items = mutableListOf("Item 1", "Item 2", "Item 3", "Item 4", "Item 5") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_pull_to_refresh) swipeRefreshLayout = findViewById(R.id.swipeRefreshLayout) recyclerView = findViewById(R.id.recyclerView) recyclerView.layoutManager = LinearLayoutManager(this) recyclerView.adapter = ItemAdapter(items) // TODO: Add pull-to-refresh logic here } } // TODO: Create ItemAdapter class for RecyclerView
import android.os.Bundle import android.os.Handler import android.os.Looper import androidx.appcompat.app.AppCompatActivity import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.LinearLayoutManager import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.TextView class PullToRefreshScreen : AppCompatActivity(), SwipeRefreshLayout.OnRefreshListener { private lateinit var swipeRefreshLayout: SwipeRefreshLayout private lateinit var recyclerView: RecyclerView private val items = mutableListOf("Item 1", "Item 2", "Item 3", "Item 4", "Item 5") private lateinit var adapter: ItemAdapter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_pull_to_refresh) swipeRefreshLayout = findViewById(R.id.swipeRefreshLayout) recyclerView = findViewById(R.id.recyclerView) recyclerView.layoutManager = LinearLayoutManager(this) adapter = ItemAdapter(items) recyclerView.adapter = adapter swipeRefreshLayout.setOnRefreshListener(this) } override fun onRefresh() { // Show loading spinner for 2 seconds Handler(Looper.getMainLooper()).postDelayed({ for (i in items.indices) { items[i] = items[i].removeSuffix(" - refreshed") + " - refreshed" } adapter.notifyDataSetChanged() swipeRefreshLayout.isRefreshing = false }, 2000) } } class ItemAdapter(private val items: List<String>) : RecyclerView.Adapter<ItemAdapter.ViewHolder>() { class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val textView: TextView = itemView.findViewById(android.R.id.text1) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val view = LayoutInflater.from(parent.context) .inflate(android.R.layout.simple_list_item_1, parent, false) return ViewHolder(view) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { holder.textView.text = items[position] } override fun getItemCount(): Int = items.size }
This solution uses SwipeRefreshLayout to enable the pull-to-refresh gesture. The activity implements SwipeRefreshLayout.OnRefreshListener to listen for the pull gesture.
When the user pulls down, onRefresh() is called. We simulate a 2-second loading delay using a Handler and postDelayed. After the delay, we update each item by appending " - refreshed" (removing duplicates if any), then notify the adapter to refresh the list UI.
The refreshing spinner is stopped by setting isRefreshing = false. The ItemAdapter is a simple RecyclerView adapter that shows each item in a text view.
This approach keeps the UI responsive and provides a familiar pull-to-refresh experience.
------------------------- | PullToRefreshScreen | ------------------------- | ↓ Pull down to refresh | |-----------------------| | Item 1 - refreshed | | Item 2 - refreshed | | Item 3 - refreshed | | Item 4 - refreshed | | Item 5 - refreshed | -------------------------
Practice
SwipeRefreshLayout in an Android app?Solution
Step 1: Understand SwipeRefreshLayout role
SwipeRefreshLayoutis a layout that wraps scrollable views to add pull-to-refresh support.Step 2: Identify its main function
Its main function is to detect swipe down gestures and show a refresh spinner to update content.Final Answer:
To enable pull-to-refresh functionality on a scrollable view -> Option CQuick Check:
SwipeRefreshLayout = Pull-to-refresh wrapper [OK]
- Confusing SwipeRefreshLayout with navigation components
- Thinking it handles background tasks automatically
- Using it without wrapping a scrollable view
swipeRefresh in Kotlin?Solution
Step 1: Recall SwipeRefreshLayout listener syntax
The correct method issetOnRefreshListenerwith a lambda for refresh action.Step 2: Match the correct Kotlin syntax
swipeRefresh.setOnRefreshListener { refreshData() } uses the correct method and lambda syntax:swipeRefresh.setOnRefreshListener { refreshData() }.Final Answer:
swipeRefresh.setOnRefreshListener { refreshData() } -> Option BQuick Check:
Listener method = setOnRefreshListener [OK]
- Using incorrect property names like onRefresh or refreshListener
- Calling refreshData() outside a lambda
- Passing function reference without parentheses incorrectly
swipeRefresh.setOnRefreshListener {
fetchData()
swipeRefresh.isRefreshing = false
}Solution
Step 1: Analyze refresh listener behavior
When user pulls down,setOnRefreshListenertriggers, callingfetchData()and then setsisRefreshing = false.Step 2: Understand spinner visibility
Spinner shows when refresh starts, then hides afterisRefreshingis set false, so it appears briefly.Final Answer:
The refresh spinner shows briefly, fetchData() runs, then spinner hides -> Option AQuick Check:
Spinner visibility controlled by isRefreshing [OK]
- Assuming spinner never shows if isRefreshing set false immediately
- Thinking fetchData() must be asynchronous here
- Confusing spinner behavior with background thread errors
swipeRefresh.setOnRefreshListener {
fetchData()
}Solution
Step 1: Identify spinner control
The spinner stays visible untilisRefreshingis set to false manually.Step 2: Check code for isRefreshing update
The code does not setswipeRefresh.isRefreshing = false, so spinner never hides.Final Answer:
Missing setting swipeRefresh.isRefreshing = false after fetchData() -> Option AQuick Check:
Stop spinner by setting isRefreshing false [OK]
- Forgetting to stop spinner after refresh
- Misplacing fetchData() call outside listener
- Incorrectly wrapping views causing no refresh
Solution
Step 1: Wrap RecyclerView in SwipeRefreshLayout
SwipeRefreshLayout must wrap the scrollable RecyclerView to detect pull gestures.Step 2: Set refresh listener and stop spinner
UsesetOnRefreshListenerto call data fetch, then setisRefreshing = falseafter update to hide spinner.Final Answer:
Wrap RecyclerView in SwipeRefreshLayout, setOnRefreshListener to fetch data, then set isRefreshing false after update -> Option DQuick Check:
Wrap + listener + stop spinner = correct setup [OK]
- Not wrapping RecyclerView inside SwipeRefreshLayout
- Forgetting to set isRefreshing false after refresh
- Calling fetchData() outside listener causing no refresh trigger
Ready to prove it?
Pass the test and this pattern moves unknown
