今回、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からお気軽にフィードバックください。