A production-ready Android inventory management application built with Kotlin, Jetpack Compose, Room Database, and Hilt Dependency Injection, following MVVM + Clean Architecture principles.
This project follows a three-layer clean architecture pattern:
app/
├── src/main/kotlin/com/example/craftnook/
│ ├── data/ # Data Layer
│ │ ├── database/ # Room entities and DAOs
│ │ ├── network/ # Retrofit API interfaces
│ │ ├── repository/ # Repository implementations
│ │ └── di/ # Data layer dependency injection
│ │
│ ├── domain/ # Domain Layer (Business Logic)
│ │ ├── model/ # Data models and domain objects
│ │ ├── usecase/ # Use cases / business logic
│ │ └── repository/ # Repository interfaces
│ │
│ ├── ui/ # Presentation Layer
│ │ ├── screen/ # Jetpack Compose screens
│ │ ├── viewmodel/ # ViewModels
│ │ ├── component/ # Reusable composables
│ │ ├── theme/ # Material 3 theming
│ │ ├── navigation/ # Navigation setup
│ │ └── di/ # UI layer dependency injection
│ │
│ └── MyApplication.kt # Application class with Hilt setup
│
└── src/test/ # Unit tests
- Manages all data sources (local database, remote API)
- Room database setup with entities and DAOs
- Retrofit API clients and network calls
- Repository implementations that abstract data sources
- Dependency injection for data layer components
Key Components:
Entityclasses for Room database tablesDaointerfaces for database operationsApiinterfaces for REST endpointsRepositoryimplementations combining Room + Retrofit
- Contains business logic and use cases
- Independent of Android framework
- Defines repository interfaces (contracts)
- Data models used across the app
- Can be tested without any Android dependencies
Key Components:
UseCaseclasses for business operationsModeldata classesRepositoryinterfaces (contracts)
- Jetpack Compose screens and components
- ViewModels for state management
- Navigation setup with Navigation Compose
- Material 3 theming and styling
- Dependency injection for UI components
Key Components:
Screencomposables for full screensViewModelclasses for UI stateComponentcomposables for reusable UI elementsThemesetup for Material Design 3
- Jetpack Compose 1.5.4 - Modern declarative UI framework
- Material 3 - Latest Google Material Design guidelines
- Navigation Compose - Type-safe navigation
- MVVM - Model-View-ViewModel pattern
- ViewModel - Lifecycle-aware state management
- StateFlow - Reactive state container
- Room Database 2.6.0 - Local SQLite database
- Retrofit 2.9.0 - Type-safe REST client
- OkHttp - HTTP client with interceptors
- Hilt 2.48 - Dependency injection framework
- Hilt Navigation Compose - ViewModel injection in Compose
- Kotlin Coroutines 1.7.3 - Asynchronous programming
- Coroutine Test - Testing support
- JUnit 4 - Unit testing framework
- Mockk - Mocking library for Kotlin
- Espresso - UI testing framework
- Compose UI Testing - Compose-specific UI tests
// Entity - Maps to a Room table
@Entity(tableName = "articles")
data class ArticleEntity(
@PrimaryKey val id: String,
val title: String,
val content: String
)
// DAO - Database Access Object
@Dao
interface ArticleDao {
@Query("SELECT * FROM articles")
fun getAll(): Flow<List<ArticleEntity>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(article: ArticleEntity)
}
// Database - Room database configuration
@Database(entities = [ArticleEntity::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun articleDao(): ArticleDao
}// Repository Implementation
class ArticleRepositoryImpl(
private val articleApi: ArticleApi,
private val articleDao: ArticleDao
) : ArticleRepository {
override fun getArticles(): Flow<List<Article>> {
return articleDao.getAll().map { entities ->
entities.map { it.toDomain() }
}
}
}// Use Case - Business Logic
class GetArticlesUseCase(
private val repository: ArticleRepository
) {
operator fun invoke(): Flow<List<Article>> {
return repository.getArticles()
}
}// ViewModel - State Management
@HiltViewModel
class ArticleViewModel @Inject constructor(
private val getArticlesUseCase: GetArticlesUseCase
) : ViewModel() {
val articles = getArticlesUseCase()
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(),
initialValue = emptyList()
)
}// Compose Screen
@Composable
fun ArticleScreen(
viewModel: ArticleViewModel = hiltViewModel()
) {
val articles by viewModel.articles.collectAsState()
LazyColumn {
items(articles) { article ->
ArticleCard(article)
}
}
}Application Class:
@HiltAndroidApp
class MyApplication : Application()Module Example:
@Module
@InstallIn(SingletonComponent::class)
object RepositoryModule {
@Singleton
@Provides
fun provideArticleRepository(
api: ArticleApi,
dao: ArticleDao
): ArticleRepository {
return ArticleRepositoryImpl(api, dao)
}
}| Dependency | Purpose | Version |
|---|---|---|
androidx.compose.ui:ui |
Compose UI framework | 1.5.4 |
androidx.compose.material3:material3 |
Material Design 3 | 1.1.2 |
androidx.room:room-runtime |
Local database | 2.6.0 |
com.google.dagger:hilt-android |
Dependency injection | 2.48 |
com.squareup.retrofit2:retrofit |
REST client | 2.9.0 |
androidx.lifecycle:lifecycle-viewmodel-ktx |
ViewModel | 2.6.1 |
- Android Studio Koala or newer
- JDK 17 or newer
- Android SDK 34
- Minimum API Level 24
- Clone the repository
- Open in Android Studio
- Sync Gradle files
- Run on emulator or physical device
- Create Domain Model (
domain/model/) - Define Repository Interface (
domain/repository/) - Create Use Case (
domain/usecase/) - Implement Repository (
data/repository/) - Create Room Entity & DAO (
data/database/) - Create API Interface (
data/network/) - Add ViewModel (
ui/viewmodel/) - Build Compose Screen (
ui/screen/) - Wire Up Navigation
./gradlew test./gradlew connectedAndroidTest./gradlew testDebugUnitTest --tests "*" --coverage| Command | Purpose |
|---|---|
./gradlew build |
Build release APK |
./gradlew assembleDebug |
Build debug APK |
./gradlew installDebug |
Install on connected device |
./gradlew test |
Run unit tests |
./gradlew connectedAndroidTest |
Run instrumented tests |
- ✅ Keep layers independent and testable
- ✅ Use interfaces for abstraction
- ✅ Inject dependencies via Hilt
- ✅ Use coroutines for async operations
- ✅ Use
StateFlowfor state management - ✅ Hoist state to ViewModel
- ✅ Create reusable composables
- ✅ Use Material 3 components
- ✅ Use Room for type-safe database access
- ✅ Return
Flow<>from DAOs for reactive updates - ✅ Use migrations for schema changes
- ✅ Test use cases and repositories
- ✅ Mock external dependencies
- ✅ Test UI state in ViewModels
- Android Architecture Guide
- Jetpack Compose Documentation
- Room Database Guide
- Hilt Dependency Injection
- Kotlin Coroutines
This project is licensed under the MIT License - see the LICENSE file for details.