0
0
Android Kotlinmobile~7 mins

Repository pattern in Android Kotlin

Choose your learning style9 modes available
Introduction

The Repository pattern helps keep your app organized by separating data access from the rest of your code. It acts like a middleman between your app and data sources.

When you want to get data from different places like a database or the internet without mixing code.
When you want to make your app easier to test by isolating data logic.
When you want to change where data comes from without changing the app's main code.
When you want to keep your code clean and easy to understand.
When you want to handle caching data smoothly.
Syntax
Android Kotlin
interface UserRepository {
    suspend fun getUser(userId: String): User
}

class UserRepositoryImpl(
    private val remoteDataSource: RemoteDataSource,
    private val localDataSource: LocalDataSource
) : UserRepository {
    override suspend fun getUser(userId: String): User {
        // Implementation to get user from local or remote
        TODO("Not yet implemented")
    }
}

The repository is usually an interface with one or more implementations.

It hides where the data comes from, so the rest of the app just asks the repository.

Examples
Defines a repository interface for products.
Android Kotlin
interface ProductRepository {
    suspend fun getProducts(): List<Product>
}
Implements the repository to get products from an API.
Android Kotlin
class ProductRepositoryImpl(
    private val apiService: ApiService
) : ProductRepository {
    override suspend fun getProducts(): List<Product> {
        return apiService.fetchProducts()
    }
}
Repository implementation that checks local cache first, then fetches from API if needed.
Android Kotlin
class ProductRepositoryImpl(
    private val apiService: ApiService,
    private val localDb: ProductDao
) : ProductRepository {
    override suspend fun getProducts(): List<Product> {
        val cached = localDb.getAll()
        return if (cached.isNotEmpty()) cached else {
            val fresh = apiService.fetchProducts()
            localDb.insertAll(fresh)
            fresh
        }
    }
}
Sample App

This example shows a UserRepository that first tries to get a user from local cache. If not found, it fetches from remote and saves locally. The main function fetches the same user twice to show caching.

Android Kotlin
data class User(val id: String, val name: String)

interface UserRepository {
    suspend fun getUser(userId: String): User
}

class RemoteDataSource {
    suspend fun fetchUser(userId: String): User {
        return User(userId, "Remote User")
    }
}

class LocalDataSource {
    private val cache = mutableMapOf<String, User>()
    suspend fun getUser(userId: String): User? {
        return cache[userId]
    }
    suspend fun saveUser(user: User) {
        cache[user.id] = user
    }
}

class UserRepositoryImpl(
    private val remoteDataSource: RemoteDataSource,
    private val localDataSource: LocalDataSource
) : UserRepository {
    override suspend fun getUser(userId: String): User {
        val localUser = localDataSource.getUser(userId)
        if (localUser != null) {
            return localUser
        }
        val remoteUser = remoteDataSource.fetchUser(userId)
        localDataSource.saveUser(remoteUser)
        return remoteUser
    }
}

suspend fun main() {
    val remote = RemoteDataSource()
    val local = LocalDataSource()
    val repo = UserRepositoryImpl(remote, local)

    val user1 = repo.getUser("123")
    println("First fetch: ${user1.name}")

    val user2 = repo.getUser("123")
    println("Second fetch: ${user2.name}")
}
OutputSuccess
Important Notes

Use suspend functions for repository methods when working with coroutines.

Repository pattern helps you swap data sources easily without changing UI code.

Keep repository methods simple and focused on data retrieval or saving.

Summary

The Repository pattern separates data logic from UI and business logic.

It acts as a single source of truth for data in your app.

It makes your app easier to maintain, test, and extend.