MrBovineJoni
MrBovineJoni

Reputation: 336

LiveData not being set, observer never being called

I'm trying to save an "Episode" in my MainViewModel and allow other Fragments to have access to it via that ViewModel.

In MainActivity I'm observing changes in the ViewModel, which is never being triggered. Weirdly, it works fine for my MainFeed RSS object

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    mViewModel = ViewModelProviders.of(this, mViewModelFactory).get(MainViewModel::class.java)


    mViewModel?.getMainFeed()

    setFragment(EpisodesFragment(), false)

    mViewModel?.episode?.observe(this, Observer {
        Log.d(TAG, "HERE 123")
    })
}

Here's the MainViewModel:

class MainViewModel @Inject constructor(): ViewModel() {
    val TAG: String? = MainViewModel::class.simpleName

    @Inject lateinit var api: NetworkModule

    var mainFeed: MutableLiveData<Response<RSS>> = MutableLiveData()
    var episode: MutableLiveData<Item> = MutableLiveData()

    companion object{
        fun create(activity: FragmentActivity, viewModelFactory: ViewModelProvider.Factory): MainViewModel {
            return ViewModelProviders.of(activity, viewModelFactory).get(MainViewModel::class.java)
        }
    }

    fun getMainFeed(){
        GlobalScope.launch(Dispatchers.Main) {
            val request = api.getRssFeed()
            val response = request.await()

            if(response.isSuccessful){
                Log.d(TAG, "isSuccessful")

                mainFeed.value = response
            } else {
                Log.d(TAG, "not successful")
            }
        }
    }

    fun setEpisode(item: Item?){
        Log.d(TAG, item?.description)
        episode?.value = item
    }
}

In my EpisodesFragment I'm passing MainViewModel to a RecyclerView adapter. In the layout for the Episode item I have an onClick() that calls mViewModel.setEpisode(episode)

So the clicks are registering. I set breakpoints and can see the episode item is actually there and holds data in the setEpisode() method. It just never actually gets set in the LiveData. I verified that the ViewModel is not null in any locations I've used it.

Edit: Adding code for EpisodesFragment

class EpisodesFragment @Inject constructor() : DaggerFragment() {
    var TAG: String? = EpisodesFragment::class.simpleName

    var mBinding: FragmentEpisodesBinding? = null
    var mRV: RecyclerView? = null
    var mAdapter: EpisodesRecyclerViewAdapter? = null

    var mItems: MutableList<Item> = ArrayList<Item>()

    @Inject
    lateinit var mViewModelFactory: ViewModelProvider.Factory
    var mViewModel: EpisodesViewModel? = null
    var mMainViewModel: MainViewModel? = null

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        super.onCreateView(inflater, container, savedInstanceState)

        mBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_episodes, container, false)
        mBinding?.executePendingBindings()


        return mBinding?.root
    }

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

        mViewModel = ViewModelProviders.of(this,
            mViewModelFactory
        ).get(EpisodesViewModel::class.java)

        mMainViewModel = ViewModelProviders.of(
            this,
            mViewModelFactory
        ).get(MainViewModel::class.java)

        if (mBinding?.rv != null) {
            mRV = mBinding?.rv
            val context: Context? = mRV?.context

            mRV?.setHasFixedSize(true)

            mAdapter = EpisodesRecyclerViewAdapter(mMainViewModel)

            mRV?.adapter = mAdapter

            val layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
            val dividerItemDecoration = DividerItemDecoration(
                mRV?.context,
                layoutManager.orientation
            )
            mRV?.addItemDecoration(dividerItemDecoration)
            mRV?.layoutManager = layoutManager

        }

        mViewModel?.getMainFeed()

        mViewModel?.mainFeed?.observe(viewLifecycleOwner, Observer {
            mItems.addAll(it?.body()?.channel?.item!!)

            Log.d(TAG, mItems.get(0).description)
            mAdapter?.setItems(mItems)
            mAdapter?.notifyDataSetChanged()
        })
    }
}

Upvotes: 1

Views: 610

Answers (1)

Sergio
Sergio

Reputation: 30715

Try to use activity property instead of this in your EpisodesFragment when you are requesting MainViewModel:

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

    mMainViewModel = ViewModelProviders.of(
        activity,
        mViewModelFactory
    ).get(MainViewModel::class.java)

    // ...
}

ViewModelProviders.of may return different MainViewModel instance for fragment.

Upvotes: 2

Related Questions