スキル一覧に戻る
ShotaIuchi

android-architecture

by ShotaIuchi

0🍴 0📅 2026年1月25日
GitHubで見るManusで実行

SKILL.md


name: Android Architecture description: This skill should be used when implementing Android features, creating ViewModels, setting up Repositories, using Hilt, implementing Jetpack Compose, or following MVVM/UDF patterns on Android. references:

  • path: ../../references/common/clean-architecture.md
  • path: ../../references/common/testing-strategy.md
  • path: ../../references/languages/kotlin/coroutines.md
  • path: ../../references/platforms/android/architecture.md external:

External IDs are resolved via ~/.claude/references/external-links.yaml

or project-specific dotclaude/references/external-links.yaml


Android Architecture

MVVM / UDF / Repository patterns based on Google's official Android Architecture Guide.

Core Principles

  1. Separation of Concerns - Clearly separate UI logic from business logic
  2. Data-Driven UI - UI only reflects state
  3. Single Source of Truth (SSOT) - Repository is the SSOT for data
  4. Unidirectional Data Flow (UDF) - Events flow upstream, state flows downstream
    • Example: User taps "Refresh" button → ViewModel receives event → UseCase fetches data → Repository returns Result → ViewModel updates UiState → Compose recomposes UI
UI Layer → Domain Layer → Data Layer
    ↑                          |
    └──────── State ───────────┘

Layer Structure

LayerResponsibilityKey Components
UIDisplay and user interactionActivity, Fragment, Compose, ViewModel
DomainBusiness logic (optional layer)UseCase, Domain Model
DataData retrieval and persistenceRepository, DataSource, DAO, API

Domain Layer Details

The Domain layer is optional but recommended for complex applications:

  • UseCase: Encapsulates a single business operation. Coordinates between UI and Data layers, contains business rules, and is reusable across multiple ViewModels.
  • Domain Model: Pure Kotlin data classes representing business entities. Independent of framework-specific types (no Room annotations, no API response models).

Directory Structure

app/src/main/java/com/example/app/
├── ui/                 # UI Layer
│   └── feature/
│       ├── FeatureScreen.kt
│       ├── FeatureViewModel.kt
│       └── FeatureUiState.kt
├── domain/             # Domain Layer
│   ├── model/
│   └── usecase/
├── data/               # Data Layer
│   ├── repository/
│   ├── local/
│   └── remote/
└── di/                 # DI modules

Naming Conventions

TypePatternExample
ViewModel{Feature}ViewModelUserListViewModel
UI State{Feature}UiStateUserListUiState
UseCase{Action}{Entity}UseCaseGetUsersUseCase
Repository{Entity}RepositoryUserRepository

Hilt Dependency Injection

Basic Hilt module structure:

@Module
@InstallIn(SingletonComponent::class)
object DataModule {
    @Provides
    @Singleton
    fun provideUserRepository(api: UserApi, dao: UserDao): UserRepository =
        UserRepositoryImpl(api, dao)
}

@Module
@InstallIn(ViewModelComponent::class)
object DomainModule {
    @Provides
    fun provideGetUsersUseCase(repository: UserRepository): GetUsersUseCase =
        GetUsersUseCase(repository)
}

Jetpack Compose State Management

State hoisting and remember best practices:

// State hoisting: lift state to caller
@Composable
fun UserListScreen(viewModel: UserListViewModel = hiltViewModel()) {
    val uiState by viewModel.uiState.collectAsStateWithLifecycle()
    UserListContent(
        users = uiState.users,
        onRefresh = viewModel::refresh
    )
}

// remember for expensive calculations
@Composable
fun UserListContent(users: List<User>, onRefresh: () -> Unit) {
    val sortedUsers = remember(users) { users.sortedBy { it.name } }
    // ...
}

Error Handling Patterns

Using sealed class for result handling:

sealed class Result<out T> {
    data class Success<T>(val data: T) : Result<T>()
    data class Error(val exception: Throwable) : Result<Nothing>()
    object Loading : Result<Nothing>()
}

// In ViewModel
private val _uiState = MutableStateFlow<UserListUiState>(UserListUiState.Loading)
val uiState: StateFlow<UserListUiState> = _uiState.asStateFlow()

fun loadUsers() {
    viewModelScope.launch {
        getUsersUseCase().collect { result ->
            _uiState.value = when (result) {
                is Result.Success -> UserListUiState.Success(result.data)
                is Result.Error -> UserListUiState.Error(result.exception.message)
                is Result.Loading -> UserListUiState.Loading
            }
        }
    }
}

Navigation with type-safe arguments:

// Define routes
sealed class Screen(val route: String) {
    object UserList : Screen("users")
    object UserDetail : Screen("users/{userId}") {
        fun createRoute(userId: String) = "users/$userId"
    }
}

// NavHost setup
NavHost(navController, startDestination = Screen.UserList.route) {
    composable(Screen.UserList.route) {
        UserListScreen(onUserClick = { userId ->
            navController.navigate(Screen.UserDetail.createRoute(userId))
        })
    }
    composable(
        route = Screen.UserDetail.route,
        arguments = listOf(navArgument("userId") { type = NavType.StringType })
    ) { backStackEntry ->
        UserDetailScreen(userId = backStackEntry.arguments?.getString("userId"))
    }
}

Detailed References

スコア

総合スコア

50/100

リポジトリの品質指標に基づく評価

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

0/10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

レビュー

💬

レビュー機能は近日公開予定です