結論から言うと現時点では難しいのではないかと思います 前提としてDagger Hiltを使うことを想定しています

ここでいう「安全に」とはDIするインスタンスが適切なComponentで管理されていることを指します

HiltではActivityならActivityComponent、ViewModelならViewModelComponentといったように、生存期間の違いに応じて自動的に異なるComponentでインスタンスが管理されます

https://dagger.dev/hilt/components.html

Daggerを使ってViewModelをAssisted Injectする場合、@HiltViewModelを同時につか

Daggerを使ってViewModelをAssisted Injectするコードはビルドもできますし、インスタンスが注入されもします

しかし、ViewModelをAssisted Injectすると本来ViewModelComponentで管理したいところがActivityComponentあるいはFragmentComponentの管理下に置かれます(これはViewModelをどこで保持しているかによります)

これのデメリットとして、

  1. ViewModelにViewModelScopedのインスタンスがDIできない
  2. ViewModelにActivityScopedやFragmentScopedのインスタンスがDIできてしまう

ことが挙げられます

特に2では、生存期間が比較的長いViweModelから生存期間が短いインスタンスを保持できてしまうのでメモリリークの可能性があります

ActivityScopedなインスタンスでActivityをDIしていたりすると気づかないうちにActivityがリークしているということが起こりえます

さらに、Activityが再生成されたときにViewModelが保持しているインスタンスが残ったままになる問題が起こります

例えばこのようなコードが書けてしまい、Activityの再生成前はActivityとViewModelで同じActivityScopedDataのインスタンスを参照しますが、再生成された後は異なるインスタンスを参照します

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    private val viewModel by viewModels<MyViewModel> {
        produceViewModelFactory(this) {
            factory.create()
        }
    }

    @Inject
    lateinit var factory: MyViewModel.Factory

    // Activity再生成後は別のインスタンスがDIされる
    @Inject
    lateinit var activityScopedData: ActivityScopedData 
}

class MyViewModel @AssistedInject constructor(
   // Activity再生成後も保持し続けられる   
   val activityScopedData: ActivityScopedData 
) : ViewModel()

@ActivityScoped
class ActivityScopedData @Inject constructor()

これはActivityScopedDataを@ActivityRetainedScopedで管理すれば同じインスタンスになるので注意して書けば意図通り動くでしょう

しかし、ViewModelがViewModelComponentで管理できていればビルドエラーで気付ける問題なので比較的危険な状態であるといえます

すでにHiltViewModelかつAssisted Injectをサポートしてほしい旨の議論は下記のissueでなされていますが、いまのところ進展はないようです

https://github.com/google/dagger/issues/2287

代替案としてSavedStateHandleをViewModelにDIしてそこから値を取得する方法が挙げられています

SavedStateHandleを使うにしてもgetするときにnullableでとれるのでそこに目をつぶればこちらでもいい気はします

ViewModelのAssisted Injectサポートは個人的にはあるととても嬉しい機能なので期待したいです