Skip to main content

Koject v1.1.0 - Androidのサポート強化

Mori Atsushi

今回、Androidのサポートを強化したKoject v1.1.0をリリースしました。 この記事では、v1.1.0で追加された機能と、それを実現するためのComponent機能について紹介します。

Read in English →

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? {
/* ... */
}
}

利用には追加の依存関係が必要です。 詳細はドキュメントを確認してください。

更新 (2023/03/14)

v1.2.0でinjectViewModelslazyViewModelsに名称が変更されました。

// 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できないことに注意してください。

カスタムコンポーネントの作り方はドキュメントで紹介しています。

Experimental

コンポーネント機能は実験的なAPIです。将来的に変更される可能性があります。

Kojectは進化します

Koject v1.1.0は、Androidアプリケーション開発を強力に支援してくれると信じています。 より一層使いやすいライブラリにするため、今後もさらなる機能追加を予定しています。

気づいたことがあれば、Issueからお気軽にフィードバックください。