LoginSignup
0
0

More than 1 year has passed since last update.

【Android】onCreate()の外側でViewModelを使いたい場合の初期化方法

Posted at

はじめに

公式のドキュメントでは、onCreate()内でViewModelをリクエストすることが推奨されています。

通常は、アクティビティ オブジェクトの onCreate() メソッドが最初に呼び出されたときに、ViewModel をリクエストします。

onCreate()ViewModelを初期化する場合は次のようになるでしょうか。

import androidx.activity.ComponentActivity
import androidx.activity.viewModels
...

class ExampleActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        val viewModel: ExampleModel by viewModels()
        setContent {
            ...
        }
    }
}

onCreate()でViewModelを初期化する場合の問題

通常の使用用途であれば、ライフサイクルに従ってonCreate()ViewModelを初期化すればよいのですが、もし、onResume()onPause()などでViewModelに実装されたロジックを呼び出したい場合はどうすればよいのでしょうか?

もちろん、onCreate()内でval viewModel: ExampleViewModel by viewModels()を実行してしまっているため、他のメソッドでは呼び出すことができません。

それでは、onCreate()の外側でby viewModels()を呼び出してアクティビティ内でいつでもViewModelを使えるようにすればよいのでしょうか?

class ExampleActivity : ComponentActivity() {
    val viewModel: ExampleViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        setContent {
            ...
        }
    }

これはアンチパターンな気がします。公式では、onCreate()の中でリクエストすべきと書かれているため、ライフサイクルに沿わない初期化方法はあまり良くないでしょう。

lateinitとhiltViewModel()を使って解決する

そこで、lateinitを使ってonCreate()の外側でViewModelを定義し、onCreate()で呼び出されているsetContent()内でhiltViewModel()を呼び出すことで安全にViewModelを初期化する方法を考えました。

class NfcActivity : ComponentActivity() {
    lateinit var pendingIntent: PendingIntent
    lateinit var nfcAdapter: NfcAdapter

    lateinit var viewModel: ExampleModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        ...

        setContent {
            viewModel = hiltViewModel()
            val uiState by viewModel.uiState.collectAsState()
            ...
        }
    }
    
    ...

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        setIntent(intent)
        if (intent != null && viewModel != null) {
            viewModel.processIntent(intent)
        }
    }
}

これにより、上記のようにアクティビティに定義されたonNewIntent()内でも安全にViewModelのメソッドを呼び出すことができるようになりました。そして、その処理の結果によりuiStateを変更させ、コンポーザブルに表示する値等も変更できるようになります。

hiltViewModel()などを呼び出すために必要なHiltの設定方法などについては、こちらのnowinandroidのリポジトリを参照してください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0