
今回、Androidのサポートを強化したKoject v1.1.0をリリースしました。 この記事では、v1.1.0で追加された機能と、それを実現するためのComponent機能について紹介します。
ViewModelをinjectする
Androidアプリケーション開発では、AndroidXのViewModelにRepository等の依存関係を追加し、ActivityやFragmentから利用することが一般的です。 Koject v1.1.0を使うことで、ViewModelの依存関係を自動的に管理できます。
まず最初に、ViewModelで利用するクラスに@Providesアノテーションをつけ、DIコンテナに登録します。@Singletonをつけることでシングルトンとして扱うことができます。
@Singleton
@Provides
class UserRepository {
/* ... */
}
@Singleton
@Provides
class ContentRepository {
/* ... */
}
次に、ViewModelを定義します。
コンストラクタでDIコンテナに登録したクラスを受け取ることができます。
ViewModelには@Providesアノテーションと@ViewModelComponentアノテーションをつけてください。
@Provides
@ViewModelComponent
class TopViewModel(
private val userRepository: UserRepository,
private val contentRepository: ContentRepository,
): ViewModel() {
/* ... */
}
最後に、ComponentActivity.injectViewModels()関数を使ってViewModelを取得します。
class TopActivity : ComponentActivity() {
private val viewModel: TopViewModel by injectViewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
/* ... */
}
}
FragmentではFragment.injectViewModels()関数を使ってください。
class TopFragment : Fragment() {
private val viewModel: TopViewModel by injectViewModels()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
/* ... */
}
}
利用には追加の依存関係が必要です。 詳細はドキュメントを確認してください。
v1.2.0でinjectViewModelsはlazyViewModelsに名称が変更されました。
// Until v1.1.0
private val viewModel: TopViewModel by injectViewModels()
// Since v1.2.0
private val viewModel: TopViewModel by lazyViewModels()
Composeで利用する
Koject 1.1.0ではJetpack Compose及び Compose Multiplatformのサポートも追加しました。
rememberInject()関数を使うことで配布されたクラスをComposable関数で利用することができます。
@Composable
fun Sample(
controller: SampleController = rememberInject()
) {
/* ... */
}
rememberInject()はComposable関数内でも呼び出すことができますが、デフォルト引数として利用することをおすすめします。
そうすることで、テスト時等に差し替えやすくなります。
Compmosable関数内でinject()関数を使わないように注意してください。
レンダリングごとにインスタンスを作成したり、何度もinject処理が行われることで、パフォーマンスが低下する恐れがあります。
@Composable
fun Sample(
controller: SampleController = inject() // DO NOT!!
) {
/* ... */
}
こちらもセットアップ方法はドキュメントを確認してください。
Component機能
ViewModelには、状態を保存するSavedStateHandleをinjectすることができます。
@Provides
@ViewModelComponent
class SavedStateViewModel(
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
/* ... */
}
SavedStateHandleのようなプラットフォームで作成されるインスタンスを配布するため、Kojectは新たにComponent機能を追加しました。
ComponentはDIコンテナに登録する型をグルーピングしたものです。 デフォルトでは、全ての型はルート コンポーネントに登録されます。 コンポーネントのアノテーションを付けることで、別のコンポーネントに登録することができます。
// Registered in RootComponent
@Provides
class NormalClass
// Registered in SomeComponent
@SomeComponent
@Provides
class ComponentClass
Componentに登録された型は、同じコンポーネント内の型とルートコンポーネントの型のみを参照できます。

また、コンポーネントに対して追加の依存関係を配布できます。

Kojectでは@ViewModelComponentがデフォルトで定義されており、SavedStateHandleを@ViewModelComponentに追加しています。
そのため、@ViewModelComponent 以外にSavedStateHandleをinjectできないことに注意してください。
カスタムコンポーネントの作り方はドキュメントで紹介しています。
コンポーネント機能は実験的なAPIです。将来的に変更される可能性があります。
Kojectは進化します
Koject v1.1.0は、Androidアプリケーション開発を強力に支援してくれると信じています。 より一層使いやすいライブラリにするため、今後もさらなる機能追加を予定しています。
気づいたことがあれば、Issueからお気軽にフィードバックください。
