1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

AndroidでViewModelのLiveDataをアプリケーションで共有する

Posted at

概要

AndroidでViewModelに保持したLiveDataの値をアプリケーションで共有したい場合のメモ

方針

本来の仕様では起動中のActivityのインスタンスとViewModelが1対1で対応するため、
Activityのインスタンスが変わってしまったり、異なるActivityのインスタンスからLiveDataをobserveしても、
変更検知ができません

class MyActivity : AppCompatActivity() {
  private val userViewModel: UserViewModel by lazy { ViewModelProviders.of(this).get(MyViewModel::class.java) }
  override fun onCreate(savedInstanceState: Bundle?) {    
    userViewModel.user.observe(this, Observer<User>{ user ->
      // OtherActivityでの変更は検知できない
    })
  }
}

class OtherActivity : AppCompatActivity() {
  private val userViewModel: UserViewModel by lazy { ViewModelProviders.of(this).get(MyViewModel::class.java) }
  override fun onCreate(savedInstanceState: Bundle?) {    
    userViewModel.user.observe(this, Observer<User>{ user ->
      // 変更検知できる
    })
    // データの更新を実行
    userViewModel.fetch()
  }
}

ViewModelProvider.Factory を継承したクラスを作成し、
ViewModelのクラスの名前で ViewModelProviders から取得するViewModelが
一意になるようにすることでアプリケーション内でLievDataを共有できるようにしました。

実装したコード

ViewModelProvider.Factory を継承した ViewModelFactory というクラスを作成

class ViewModelFactory: ViewModelProvider.Factory {

    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        if (ViewModel::class.java.isAssignableFrom(modelClass)) {
            val key = modelClass.toString()
            return if(hashMapViewModel.containsKey(key)){
                getViewModel(key) as T
            } else {
                val vm: T?
                try {
                    vm = modelClass.newInstance()
                } catch (e: IllegalAccessException) {
                    throw RuntimeException("Cannot create an instance of $modelClass", e)
                } catch (e: InstantiationException) {
                    throw RuntimeException("Cannot create an instance of $modelClass", e)
                } catch (e: InvocationTargetException) {
                    throw RuntimeException("Cannot create an instance of $modelClass", e)
                }
                addViewModel(key, vm)
                getViewModel(key) as T
            }
        }
        throw IllegalArgumentException("Unknown ViewModel class")
    }

    companion object {
        val hashMapViewModel = HashMap<String, ViewModel>()
        fun addViewModel(key: String, viewModel: ViewModel?){
            viewModel?.let {  hashMapViewModel.put(key, it)
            }
        }
        fun getViewModel(key: String): ViewModel? {
            return hashMapViewModel[key]
        }
    }
}

使い方

LiveDataをアプリケーション内で共有したいときのみ、
下記のようにViewModel生成時に ViewModelFactory を渡してあげればOK

class MyActivity : AppCompatActivity() {
  private val viewModelFactory: ViewModelFactory = ViewModelFactory()
  private val userViewModel: UserViewModel by lazy { ViewModelProviders.of(this, viewModelFactory).get(MyViewModel::class.java) }

  override fun onCreate(savedInstanceState: Bundle?) {    
    userViewModel.users.observe(this, Observer<List<User>>{ users ->
      // LiveDataがアプリケーション全体から参照できるようになる
    })
  }
}
1
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?