Search code examples
androidkotlinandroidxparcelableandroid-viewmodel

How can I initialize an androidx ViewModel from parcelable data?


In my Android app, I pass custom data (UByteArray) from one activity to another using the parcelable interface.

I am using this data inside multiple fragments, so I rewrote the data class to extend androidx ViewModel and expose LiveData properties to the fragments. Now the UI updates are a lot nicer, but I think I am using it wrong because I overwrite all ViewModel values inside onCreate.

Now my question: What do I need to change to initialize the ViewModel only once? The following is my current code (abbreviated and renamed for this question):

class ActivityB : AppCompatActivity() {
  private val bData: ViewModelB by viewModels()
  // ...

  override fun onCreate(savedInstanceState: Bundle?) {
    // ...
    intent.getParcelableExtra<ViewModelB>("id")?.let {
      Log.e(TAG, "Found parceled bData $it")
      // This seems like a very stupid way to do it, is there a better one?
      bData.copyAll(it)
    }
  }
}

I saw that it is possible to inject SavedState into the ViewModelB constructor, but I don't have a saved state until now, and the data needs to be passed only once.

Should I change the initialization of tagData with by viewModels() to = ViewModelB(intent)?
Or do I need to extend the ViewModelFactory somehow?

Any tip here would be really appreciated, thanks.


Solution

  • Since you have a ViewModel which implements Parcelable, you can get your ViewModelB instance directly from the Intent extra.

    The Intent which is used for starting ActivityB may not be != null at the time when ActivityB is instantiated, but you can use

    lateinit var bData: ViewModelB
    

    Then in onCreate()

    bData = if(intent.hasExtra("id")) intent.getParcelableExtra<ViewModelB>("id") else ViewModelProvider(this).get(ViewModelB::class.java)