Purpose: Provides essential Android utilities, extension functions, coroutine utilities, and dependency injection setup for the entire application.
The core:android module serves as the foundation for common Android functionality across all
modules. It contains utilities that don't depend on UI or domain-specific logic, making it the
lowest-level shared module in the application.
suspendRunCatching: Safer alternative torunCatchingfor suspend functionssuspendCoroutineWithTimeout: Timeout-aware coroutine suspension- Thread-safe error handling for asynchronous operations
OneTimeEvent: Thread-safe wrapper for one-time events (navigation, messages)Resource: Offline-first data wrapper with Success/Error/Loading statesnetworkBoundResource: Complete offline-first pattern implementation
- Flow Extensions:
stateInDelayedfor performance optimization - String Extensions: Email, password, full name validation
- Number Extensions: Formatting, timestamp conversion
- Context Extensions: Activity retrieval, resource access
- Throwable Extensions: Error message extraction, state management integration
- Dispatcher Qualifiers:
@IoDispatcher,@DefaultDispatcher,@MainDispatcher - Always use injected dispatchers for testability and consistency
Use core:android when:
- You need Android-specific utilities (Context, Resources)
- Working with coroutines and need timeout or safe error handling
- Implementing repositories with offline-first patterns
- Validating user input (email, password, names)
- Managing one-time events (navigation, snackbar messages)
- Need thread-safe dispatchers for background work
Don't use core:android for:
- UI components or Compose utilities (use
core:ui) - Network operations (use
core:network) - Database operations (use
core:room) - Preferences/settings (use
core:preferences)
class MyRepositoryImpl @Inject constructor(
private val localDataSource: LocalDataSource,
private val networkDataSource: NetworkDataSource,
@IoDispatcher private val ioDispatcher: CoroutineDispatcher
) : MyRepository {
override fun getData(): Flow<Resource<List<Data>>> = networkBoundResource(
query = { localDataSource.observeData() },
fetch = { networkDataSource.getData() },
saveFetchResult = { networkData ->
localDataSource.saveData(networkData)
},
shouldFetch = { true }
)
}@HiltViewModel
class MyViewModel @Inject constructor(
private val repository: MyRepository
) : ViewModel() {
private val _uiState = MutableStateFlow(
UiState(
data = MyScreenData(),
error = OneTimeEvent(null)
)
)
val uiState = _uiState.asStateFlow()
}class MyDataSource @Inject constructor(
@IoDispatcher private val ioDispatcher: CoroutineDispatcher
) {
suspend fun fetchData() = withContext(ioDispatcher) {
// IO operation
}
}graph TD
A[core:android] --> B[androidx.core]
A --> C[kotlinx.coroutines]
A --> D[kotlinx.serialization]
A --> E[kotlinx.datetime]
A --> F[dagger.hilt]
A --> G[timber]
style A fill: #4CAF50, stroke: #333, stroke-width: 2px
style B fill: #64B5F6, stroke: #333, stroke-width: 2px
style C fill: #64B5F6, stroke: #333, stroke-width: 2px
style D fill: #64B5F6, stroke: #333, stroke-width: 2px
style E fill: #64B5F6, stroke: #333, stroke-width: 2px
style F fill: #64B5F6, stroke: #333, stroke-width: 2px
style G fill: #64B5F6, stroke: #333, stroke-width: 2px
For detailed API documentation, see the Dokka-generated API reference.
Key APIs:
- Quick Reference Guide - Common patterns and utilities
- State Management Guide - UiState and state management patterns
- Architecture Overview - Overall application architecture
This module is typically used as a dependency in other modules that require Android functionality:
dependencies {
implementation(project(":core:android"))
}All dependencies in this module are exposed as api to make them available to dependent modules.