1

Im using ViewModel with states and LiveData with one observer . I have an activity and a fragment . everything works fine until Im rotating the screen and then, the states I want to observe , clash. What can I do in order to prevent it and make it work as expected? I know I can add more observers but I don't want to solve it in this way , it may lead to problems with the other code.

MainActivity code :

    private var appsDetailsHmap = HashMap< String , AppsDetails>()

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

        progressBar = CircleProgressBarDialog(this)


        viewModel.getState().observe(this, Observer {state->
            when(state){
                is SettingsViewModelStates.GetAppsDetails->initUI(state.list)
                is SettingsViewModelStates.ShowDialog->progressBar.showOrHide(state.visibility)
                is SettingsViewModelStates.GetCachedData->setCachedSettings(state.appDetailsHmap,state.selectedApp,state.speechResultAppName)
            }
        })

        if (savedInstanceState==null){
            viewModel.initSettingsActivityUI(appsDetailsHmap)
        }
        else{
            viewModel.initCachedSettingsActivityUI()
        }

Fragment code


    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        val view= inflater.inflate(R.layout.fragment_added_apps, container, false)

        viewModel.getCachedApplist()

        return view
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        viewModel.getState().observe(viewLifecycleOwner, Observer {state->
            when(state){
                is SettingsViewModelStates.PassAppsToFragment->{
                    initRecyclerView(state.list)
                }
            }
        })
    }

ViewModel


     private var state=MutableLiveData<SettingsViewModelStates>()
     private var appsDetailsHmap=HashMap<String,AppsDetails>()
     private var addedApps= HashMap<String,Drawable?>()

     fun getState()=state as LiveData<SettingsViewModelStates>

     fun getCachedApplist(){
        if (addedApps.isEmpty()){
            getAppsList()
            println("empty")
        }
        else
            state.setValue(SettingsViewModelStates.PassAppsToFragment(addedApps))
    }

    fun initCachedSettingsActivityUI(){
        state.setValue(SettingsViewModelStates.GetCachedData(appsDetailsHmap,selectedApp,speechResultAppName))
    }

    fun initSettingsActivityUI(list:HashMap<String, AppsDetails>) {
        appsDetailsHmap=list
        state.setValue( SettingsViewModelStates.GetAppsDetails(list))
    }

states:


    sealed class SettingsViewModelStates {

    data class GetAppsDetails(val list:HashMap<String, AppsDetails>):SettingsViewModelStates()
    data class ShowDialog(val visibility: Int) : SettingsViewModelStates()
    data class PassAppsToFragment(val list:HashMap<String,Drawable?>) : SettingsViewModelStates()
    data class GetCachedData(val appDetailsHmap:HashMap<String,AppsDetails>,
                             val selectedApp: AppsDetails,
                             val speechResultAppName:String ) : SettingsViewModelStates()
}
Netanel Izhak
  • 111
  • 1
  • 4
  • `initCachedSettingsActivityUI` this won't work well. After process death, your cache will be empty, but `savedInstanceState` will be `!= null`. – EpicPandaForce May 03 '20 at 00:55
  • As for your "state", that is not state, those are commands. It looks like you would want to merge all of them together into a single class instead. – EpicPandaForce May 03 '20 at 00:55
  • @EpicPandaForce why not? the data is saved inside the ViewModel class , which is meant to survive configurations changes. Do I miss something? Or you mean That `ViewModel` could be killed and `savedInstanceState` could be`!= null` either. And about `LiveData` problem , what should I do in order to solve it? – Netanel Izhak May 03 '20 at 10:28
  • You need to merge your sealed classes into a single class because they are not distinct states, they are commands to change the state. And yes, VM can be killed but `savedInstanceState != null` will be true in certain situations. LiveData only stores latest value, but it can skip values. For commands, I'd recommend using [this custom class](https://github.com/Zhuinden/jetpack-navigation-ftue-sample/blob/b292f5b5daf58c68ccb105bbb627e45dc8857f00/app/src/main/java/com/zhuinden/jetpacknavigationdaggersavedstatehandleftueexperiment/core/events/LiveEvent.kt#L22-L82) – EpicPandaForce May 03 '20 at 12:10
  • @EpicPandaForce I tested it several times and It seems that it solved the clashing problem. However , another problem happened , I tried to create a "clashing" on purpose , and I recieved an empty list. Maybe I missed something.. I think Ill try with RxJava in the future or search for another alternative. Thanks for the help! – Netanel Izhak May 04 '20 at 17:21
  • For your setup, you could try https://github.com/Zhuinden/event-emitter/blob/2d072e2aa7984a582379cdf40b9d58e665ba6840/event-emitter-sample/src/main/java/com/zhuinden/eventemittersample/utils/LiveEvent.kt#L65 – EpicPandaForce May 04 '20 at 19:36
  • @EpicPandaForce Checked it out , I did all the steps correctly . In addition, I saw your answer here [link](https://stackoverflow.com/a/59732259/11567128) – Netanel Izhak May 05 '20 at 07:24

0 Answers0