Skip to content

kaizen-inc/Jetpack-Compose-Pagination3

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

3 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Pagination

A comprehensive Android example demonstrating modern pagination implementation using Jetpack Compose, Paging 3 library, Room database, and Retrofit. This project showcases best practices for building scalable, offline-first applications with efficient data loading and caching strategies.

πŸ“± Project Overview

This application demonstrates a complete pagination solution by fetching beer data from the Punk API and displaying it in an infinite scrolling list. The app implements:

  • Remote Mediator Pattern: Coordinates loading data from network and local database
  • Offline-First Architecture: Uses Room database as the single source of truth
  • Modern UI: Built entirely with Jetpack Compose
  • Dependency Injection: Utilizes Dagger Hilt for clean dependency management

Key Features

  • βœ… Infinite scrolling with automatic page loading
  • βœ… Offline support with local database caching
  • βœ… Pull-to-refresh functionality
  • βœ… Loading and error state handling
  • βœ… Clean architecture with separation of concerns
  • βœ… Type-safe API calls with Retrofit and Moshi

πŸ—οΈ Architecture

The project follows a clean architecture pattern with clear separation between layers:

app/src/main/kotlin/inc/kaizen/example/pagination/
β”œβ”€β”€ client/              # API models and service definitions
β”‚   β”œβ”€β”€ Beer.kt         # Data model for API response
β”‚   └── BeerApi.kt      # Retrofit API interface
β”œβ”€β”€ database/           # Local persistence layer
β”‚   β”œβ”€β”€ BeerDao.kt      # Room DAO for database operations
β”‚   β”œβ”€β”€ BeerDatabase.kt # Room database configuration
β”‚   β”œβ”€β”€ BeerEntity.kt   # Database entity
β”‚   └── Mappers.kt      # Entity ↔ Model conversion
β”œβ”€β”€ remote/             # Network coordination
β”‚   └── BeerRemoteMediator.kt  # Paging 3 RemoteMediator
β”œβ”€β”€ di/                 # Dependency injection
β”‚   └── AppModule.kt    # Hilt module providing dependencies
β”œβ”€β”€ viewmodel/          # Presentation logic
β”‚   └── BeerViewModel.kt # ViewModel with paging flow
└── ui/                 # UI components
    β”œβ”€β”€ component/
    β”‚   └── BeerScreen.kt  # Main composable screen
    └── theme/          # Material theme definitions

Component Responsibilities

1. Data Layer

BeerApi (client/BeerApi.kt)

  • Defines REST API endpoints using Retrofit
  • Fetches beer data from Punk API with pagination parameters

BeerDao (database/BeerDao.kt)

  • Provides database operations (insert, update, query, delete)
  • Returns PagingSource<Int, BeerEntity> for Paging 3 integration

BeerDatabase (database/BeerDatabase.kt)

  • Room database configuration
  • Manages database versioning and DAO access

2. Remote Mediator

BeerRemoteMediator (remote/BeerRemoteMediator.kt)

  • Core pagination logic coordinating network and database
  • Handles three load types:
    • REFRESH: Initial load, clears and reloads data
    • PREPEND: Load data before the first item (not used in this implementation)
    • APPEND: Load next page when user scrolls to the end
  • Calculates next page based on current state
  • Manages error handling for network failures

3. Dependency Injection

AppModule (di/AppModule.kt)

  • Provides singleton instances:
    • BeerDatabase: Room database instance
    • BeerApi: Retrofit service instance
    • Pager<Int, BeerEntity>: Configured Pager with 20 items per page

4. Presentation Layer

BeerViewModel (viewmodel/BeerViewModel.kt)

  • Exposes beerPagingFlow as StateFlow
  • Transforms database entities to UI models
  • Caches paging data in ViewModel scope

BeerScreen (ui/component/BeerScreen.kt)

  • Composable UI displaying beer list
  • Handles loading states and errors
  • Implements LazyColumn with paging items

πŸš€ Getting Started

Prerequisites

  • Android Studio: Hedgehog (2023.1.1) or newer
  • JDK: Version 8 or higher
  • Android SDK: API Level 24 (Android 7.0) or higher
  • Internet Connection: Required for initial data fetch

Dependencies

The project uses the following key dependencies:

// Jetpack Compose
androidx.compose.ui:ui
androidx.compose.material:material:1.5.0
androidx.activity:activity-compose:1.7.2

// Paging 3
androidx.paging:paging-runtime-ktx:3.2.0
androidx.paging:paging-compose:3.2.0

// Room Database
androidx.room:room-ktx:2.5.2
androidx.room:room-paging:2.5.2

// Retrofit & Networking
com.squareup.retrofit2:retrofit:2.9.0
com.squareup.retrofit2:converter-moshi:2.9.0

// Dagger Hilt
com.google.dagger:hilt-android:2.45
androidx.hilt:hilt-navigation-compose:1.0.0

// Image Loading
io.coil-kt:coil-compose:2.2.2

Setup Instructions

  1. Clone the repository

    git clone https://github.com/kaizen-inc/Pagination.git
    cd Pagination
  2. Open in Android Studio

    • Launch Android Studio
    • Select "Open an Existing Project"
    • Navigate to the cloned repository and click "OK"
  3. Sync Gradle

    • Android Studio should automatically prompt to sync Gradle
    • If not, click "File" β†’ "Sync Project with Gradle Files"
  4. Build the project

    ./gradlew build
  5. Run the app

    • Connect an Android device or start an emulator
    • Click the "Run" button or press Shift + F10
    • Select your device and wait for the app to install

πŸ’‘ Usage Examples

How Pagination Works

  1. Initial Load: When the app starts, RemoteMediator fetches the first page (20 items) from the API
  2. Database Storage: Items are stored in Room database
  3. UI Display: Compose UI observes the paging flow and displays items
  4. Load More: As user scrolls near the end, the next page is automatically fetched
  5. Offline Mode: If network is unavailable, app displays cached data from database

Code Walkthrough

Setting up the Pager

In AppModule.kt:

@Provides
@Singleton
fun provideBeerPager(
    beerDatabase: BeerDatabase,
    beerApi: BeerApi
): Pager<Int, BeerEntity> {
    return Pager(
        config = PagingConfig(pageSize = 20),  // Load 20 items per page
        remoteMediator = BeerRemoteMediator(beerDatabase, beerApi),
        pagingSourceFactory = {
            beerDatabase.dao.pagingSource()  // Database is source of truth
        }
    )
}

Collecting Paging Data in UI

In MainActivity.kt:

val viewModel = hiltViewModel<BeerViewModel>()
val beers = viewModel.beerPagingFlow.collectAsLazyPagingItems()
BeerScreen(beers = beers)

Displaying Items

The BeerScreen composable handles different load states and displays items efficiently:

LazyColumn {
    items(count = beers.itemCount) { index ->
        val beer = beers[index]
        if (beer != null) {
            BeerItem(beer = beer)
        }
    }
    
    // Handle loading state for next page
    item {
        if (beers.loadState.append is LoadState.Loading) {
            CircularProgressIndicator()
        }
    }
}

Customization

Changing Page Size

Modify the pageSize parameter in AppModule.kt:

config = PagingConfig(
    pageSize = 20,           // Items per page
    enablePlaceholders = false,
    prefetchDistance = 5     // Start loading when 5 items away from end
)

Using Different API

Replace the API implementation in BeerApi.kt:

interface BeerApi {
    @GET("your-endpoint")
    suspend fun getItems(
        @Query("page") page: Int,
        @Query("per_page") pageCount: Int,
    ): List<YourModel>
    
    companion object {
        const val BASE_URL = "https://your-api.com/"
    }
}

Update corresponding entity, DAO, and mappers to match your data model.

βš™οΈ Configuration

Build Configuration

  • Min SDK: 24 (Android 7.0)
  • Target SDK: 34 (Android 14)
  • Compile SDK: 34
  • Kotlin Version: 1.7.20
  • Compose Compiler: 1.4.2

ProGuard Rules

For production builds, configure proguard-rules.pro to keep necessary classes for Retrofit, Room, and Moshi.

Database Configuration

The Room database is named beer.db and is configured with fallback to destructive migration during development. For production, implement proper migration strategies.

πŸ§ͺ Testing

The project includes test structure for:

  • Unit Tests: Located in src/test/kotlin/
  • Instrumented Tests: Located in src/androidTest/kotlin/

To run tests:

# Run unit tests
./gradlew test

# Run instrumented tests (requires connected device/emulator)
./gradlew connectedAndroidTest

🀝 Contributing

Contributions are welcome! Please follow these guidelines:

  1. Fork the repository and create your feature branch

    git checkout -b feature/your-feature-name
  2. Follow code style conventions

    • Use Kotlin coding conventions
    • Format code with Android Studio's built-in formatter
    • Add meaningful comments for complex logic
  3. Write tests for new features or bug fixes

  4. Commit your changes with descriptive commit messages

    git commit -m "Add feature: description of your changes"
  5. Push to your fork and submit a pull request

    git push origin feature/your-feature-name
  6. Ensure CI checks pass and respond to code review feedback

Code Review Process

  • All submissions require review before merging
  • Address feedback promptly
  • Keep pull requests focused on a single feature or fix

πŸ› Troubleshooting

Common Issues

Issue: Build fails with "Duplicate class" error

  • Solution: Clean and rebuild project
    ./gradlew clean build

Issue: App crashes on startup

  • Solution: Check that Hilt is properly set up and @HiltAndroidApp annotation is on the Application class

Issue: Network requests fail

  • Solution:
    • Verify internet permission in AndroidManifest.xml
    • Check that the device has internet connectivity
    • Ensure the API endpoint is accessible

Issue: Database errors

  • Solution:
    • Uninstall and reinstall the app to clear database
    • Check Room schema migrations if updating database structure

Issue: Items not loading

  • Solution:
    • Check Logcat for error messages
    • Verify RemoteMediator is correctly configured
    • Ensure PagingConfig parameters are appropriate

Debug Tips

  • Enable verbose logging in RemoteMediator for pagination debugging
  • Use Android Studio's Database Inspector to view Room database contents
  • Monitor network requests with Retrofit's logging interceptor
  • Check load states in Compose UI to understand pagination status

Getting Help

πŸ“„ License

This project is licensed under the Apache License 2.0 - see the LICENSE file for details.

πŸ™ Acknowledgments

  • Punk API for providing the free beer database API
  • Android team for Jetpack Compose and Paging 3 libraries
  • Open source community for valuable feedback and contributions

Built with ❀️ using Jetpack Compose

About

An Jetpack Compose example for pagination with Paging3 library

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages