Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Observer onChanged never called

Tags:

android

kotlin

FooActivity.kt:

class FooActivity : AppCompatActivity(), LifecycleRegistryOwner {
  override fun getLifecycle(): LifecycleRegistry {
    return LifecycleRegistry(this)
  }
  ..
  // <-- here mViewModel is null
  mViewModel.getBar().observe(this, Observer<List<String>> {
    override fun onChanged(bar: List<String>) {
      // Never triggered
    }
  })
  mViewModel.init()
  // <-- here mViewModel has changed
}

The mViewModel is confirmed to change. However the observer's onChanged is never called.


Question: why doesn't it work?


Edit: FooViewModel.kt:

class FooViewModel(application: Application) : AndroidViewModel(application) {
  val baz: BazPagerAdapter? = null
  ..
  fun init(fm: FragmentManager) {
    mBar = listOf("1", "2", "3")
  }
  ..
  fun getBar(): List<String> = mBar
  ..
  fun setBaz(pager: ViewPager, periods: List<BazFragment>) {
    pager.adapter = BazPagerAdapter(mFragmentManager!!, periods)
  }
}

Edit2:

For got to mentiond, getBar already returns LiveData

fun getBar(): LiveData<List<String>> = mBar

And the onChange still wouldn't trigger.

Edit3:

class FooViewModel(application: Application) : AndroidViewModel(application) {
  private var mBar: MutableLiveData<List<String>>? = null
  ..
  fun init(fragmentManager: FragmentManager) {
    ..
    if (mBar == null) {
      mBar = MutableLiveData<List<String>>()
    }
    mBar?.value = periods
}
..
fun getBar(): LiveData<List<String>>? = mBar
like image 996
0leg Avatar asked May 29 '26 16:05

0leg


2 Answers

There is no observe method for type List.
The ViewModel has nothing to do with observing either, it is there mainly to have state that persists through configuration changes.

For observable data you want (Mutable)LiveData objects. These are lifecycle aware and manage observers for their data.

Please see the code examples here:

public class MyViewModel : ViewModel() {
    private val mBar = MutableLiveData<List<String>>()

    fun getBar(): LiveData<List<String>> = mBar

    fun init() {
        mBar.setValue(listOf("1", "2", "3"))
    }
}
like image 123
RobCo Avatar answered May 31 '26 05:05

RobCo


So the problem is when you call init method, it reassigns new instance of LiveData into mBar. And you have assigned observer to previous instance of mBar because you are calling init method after :

 mViewModel.getBar().observe(this, Observer<List<String>> {
    override fun onChanged(bar: List<String>) {
      // Never triggered
    }
  })

To solve the problem just initialise mBar with MutableLiveData and then change its value (Do not re-assign mBar with another instance).

Check following code:

class FooViewModel(application: Application) : AndroidViewModel(application) {
    private var mBar: MutableLiveData<List<String>> = MutableLiveData()

    fun init(fragmentManager: FragmentManager) {

        mBar.value = periods // Changing value only, not new instance
    }

    fun getBar(): LiveData<List<String>> = mBar
}
like image 31
chandil03 Avatar answered May 31 '26 06:05

chandil03



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!