DEV Community

myougaTheAxo
myougaTheAxo

Posted on • Originally published at zenn.dev

Pull-to-Refresh with PullToRefreshBox - Refresh State and Paging3 (v2)

Implement intuitive pull-to-refresh functionality in Compose using PullToRefreshBox. Combine it with Paging3 for seamless data loading.

Basic PullToRefreshBox Implementation

Use Material3's PullToRefreshBox for modern refresh UI:

var isRefreshing by remember { mutableStateOf(false) }

PullToRefreshBox(
    isRefreshing = isRefreshing,
    onRefresh = {
        viewModel.refreshData()
        isRefreshing = false
    },
    modifier = Modifier.fillMaxSize()
) {
    LazyColumn {
        items(items.size) { index ->
            Text(items[index])
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Managing Refresh State with ViewModel

Handle refresh logic asynchronously:

class ListViewModel(
    private val repository: DataRepository
) : ViewModel() {
    private val _isRefreshing = MutableStateFlow(false)
    val isRefreshing = _isRefreshing.asStateFlow()

    private val _items = MutableStateFlow<List<Item>>(emptyList())
    val items = _items.asStateFlow()

    fun refreshData() {
        viewModelScope.launch {
            _isRefreshing.value = true
            try {
                val newItems = repository.fetchLatest()
                _items.value = newItems
            } finally {
                _isRefreshing.value = false
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Paging3 Integration

Combine pull-to-refresh with infinite scrolling:

class PagingListViewModel(
    private val repository: DataRepository
) : ViewModel() {
    val pagingFlow = Pager(
        config = PagingConfig(pageSize = 20),
        pagingSourceFactory = { repository.pagingSource() }
    ).flow.cachedIn(viewModelScope)
}

// In Composable
val lazyPagingItems = pagingFlow.collectAsLazyPagingItems()

PullToRefreshBox(
    isRefreshing = lazyPagingItems.loadState.refresh is LoadState.Loading,
    onRefresh = { lazyPagingItems.refresh() }
) {
    LazyColumn {
        items(lazyPagingItems.itemCount) { index ->
            lazyPagingItems[index]?.let { item ->
                ItemRow(item)
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Pull-to-refresh signals data freshness. Test edge cases like concurrent refresh and error handling.

8 Android app templates on Gumroad

Top comments (0)