jpskill.com
🛠️ 開発・MCP コミュニティ

koin-patterns

Androidアプリ開発で、Koinというライブラリを使って、部品(モジュール)や範囲(スコープ)、画面のデータ管理(ViewModel)を効率的に組み込み、アプリの設計をより柔軟にするSkill。

📜 元の英語説明(参考)

Koin dependency injection patterns for Android with modules, scopes, and ViewModel injection.

🇯🇵 日本人クリエイター向け解説

一言でいうと

Androidアプリ開発で、Koinというライブラリを使って、部品(モジュール)や範囲(スコープ)、画面のデータ管理(ViewModel)を効率的に組み込み、アプリの設計をより柔軟にするSkill。

※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o koin-patterns.zip https://jpskill.com/download/10675.zip && unzip -o koin-patterns.zip && rm koin-patterns.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/10675.zip -OutFile "$d\koin-patterns.zip"; Expand-Archive "$d\koin-patterns.zip" -DestinationPath $d -Force; ri "$d\koin-patterns.zip"

完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。

💾 手動でダウンロードしたい(コマンドが難しい人向け)
  1. 1. 下の青いボタンを押して koin-patterns.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → koin-patterns フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-18
取得日時
2026-05-18
同梱ファイル
1

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

Koin 依存性注入

Koin を用いた Kotlin 向けのプラグマティックな DI です。

モジュール設定

// AppModule.kt
val appModule = module {
    // シングルトン
    single<AppDatabase> { Room.databaseBuilder(...).build() }
    single { get<AppDatabase>().userDao() }

    // ファクトリ (毎回新しいインスタンス)
    factory { DateFormatter() }
}

// NetworkModule.kt
val networkModule = module {
    single<HttpClient> {
        HttpClient(OkHttp) {
            install(ContentNegotiation) {
                json(Json { ignoreUnknownKeys = true })
            }
        }
    }

    single<AuthApi> { AuthApiImpl(get()) }
    single<UserApi> { UserApiImpl(get()) }
}

// FeatureModule.kt
val homeModule = module {
    // リポジトリ
    single<HomeRepository> { HomeRepositoryImpl(get(), get()) }

    // ユースケース
    factory { GetItemsUseCase(get()) }
    factory { GetItemUseCase(get()) }

    // ViewModel
    viewModel { HomeViewModel(get()) }
}

アプリケーション設定

class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()

        startKoin {
            androidContext(this@MyApp)
            modules(
                appModule,
                networkModule,
                homeModule,
                detailModule
            )
        }
    }
}

ViewModel インジェクション

// Compose での使用例
@Composable
fun HomeScreen(viewModel: HomeViewModel = koinViewModel()) {
    val state by viewModel.state.collectAsStateWithLifecycle()
    // ...
}

// パラメータ付きの場合
@Composable
fun DetailScreen(itemId: String) {
    val viewModel: DetailViewModel = koinViewModel { parametersOf(itemId) }
    // ...
}

// パラメータ付きの ViewModel 定義
viewModel { params ->
    DetailViewModel(
        itemId = params.get(),
        repository = get()
    )
}

スコープ

// Activity スコープ
val activityModule = module {
    scope<MainActivity> {
        scoped { NavigationController() }
    }
}

// 使用例
class MainActivity : AppCompatActivity(), KoinScopeComponent {
    override val scope: Scope by activityScope()

    val nav: NavigationController by inject()
}

クオリファイア

val networkModule = module {
    single(named("auth")) { createAuthClient() }
    single(named("default")) { createDefaultClient() }
}

// 使用例
class UserApi(
    @Named("auth") private val client: HttpClient
)

テスト

class HomeViewModelTest : KoinTest {

    @get:Rule
    val koinRule = KoinTestRule.create {
        modules(testModule)
    }

    private val testModule = module {
        single<HomeRepository> { mockk() }
        viewModel { HomeViewModel(get()) }
    }

    private val viewModel: HomeViewModel by inject()
    private val repository: HomeRepository by inject()

    @Test
    fun `loads items`() = runTest {
        coEvery { repository.getItems() } returns Result.success(listOf())
        // ...
    }
}

覚えておいてください: Koin はプラグマティックです。モジュールを整理し、ライフサイクルに合わせてスコープを使用してください。

📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

Koin Dependency Injection

Pragmatic DI for Kotlin with Koin.

Module Setup

// AppModule.kt
val appModule = module {
    // Singletons
    single<AppDatabase> { Room.databaseBuilder(...).build() }
    single { get<AppDatabase>().userDao() }

    // Factories (new instance each time)
    factory { DateFormatter() }
}

// NetworkModule.kt
val networkModule = module {
    single<HttpClient> {
        HttpClient(OkHttp) {
            install(ContentNegotiation) {
                json(Json { ignoreUnknownKeys = true })
            }
        }
    }

    single<AuthApi> { AuthApiImpl(get()) }
    single<UserApi> { UserApiImpl(get()) }
}

// FeatureModule.kt
val homeModule = module {
    // Repository
    single<HomeRepository> { HomeRepositoryImpl(get(), get()) }

    // Use Cases
    factory { GetItemsUseCase(get()) }
    factory { GetItemUseCase(get()) }

    // ViewModel
    viewModel { HomeViewModel(get()) }
}

Application Setup

class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()

        startKoin {
            androidContext(this@MyApp)
            modules(
                appModule,
                networkModule,
                homeModule,
                detailModule
            )
        }
    }
}

ViewModel Injection

// In Compose
@Composable
fun HomeScreen(viewModel: HomeViewModel = koinViewModel()) {
    val state by viewModel.state.collectAsStateWithLifecycle()
    // ...
}

// With parameters
@Composable
fun DetailScreen(itemId: String) {
    val viewModel: DetailViewModel = koinViewModel { parametersOf(itemId) }
    // ...
}

// ViewModel definition with params
viewModel { params ->
    DetailViewModel(
        itemId = params.get(),
        repository = get()
    )
}

Scopes

// Activity scope
val activityModule = module {
    scope<MainActivity> {
        scoped { NavigationController() }
    }
}

// Usage
class MainActivity : AppCompatActivity(), KoinScopeComponent {
    override val scope: Scope by activityScope()

    val nav: NavigationController by inject()
}

Qualifiers

val networkModule = module {
    single(named("auth")) { createAuthClient() }
    single(named("default")) { createDefaultClient() }
}

// Usage
class UserApi(
    @Named("auth") private val client: HttpClient
)

Testing

class HomeViewModelTest : KoinTest {

    @get:Rule
    val koinRule = KoinTestRule.create {
        modules(testModule)
    }

    private val testModule = module {
        single<HomeRepository> { mockk() }
        viewModel { HomeViewModel(get()) }
    }

    private val viewModel: HomeViewModel by inject()
    private val repository: HomeRepository by inject()

    @Test
    fun `loads items`() = runTest {
        coEvery { repository.getItems() } returns Result.success(listOf())
        // ...
    }
}

Remember: Koin is pragmatic. Keep modules organized, use scopes for lifecycle.