ybybyb
ybybyb

Reputation: 1739

Why doesn't the data persist when I use LiveData in the ViewModel?

I am switching the screen using the Navigation Component.

In the fragment screen of the bottom A menu, i can add a recyclerview item dynamically through the button.

If i press the button on this screen, it moves to another fragment where data can be selected.

If i select data on the converted fragment screen, it returns to the previous screen and adds a recycler view item based on the selected data.

This process is repeated.

However, even if I repeat this process, the item is not dynamically added.

I add items to the List of LiveData by using the ViewModel, but as a result of debugging, the size of the list type of LiveData does not increase from only one.

At least as far as I know the data should be persisted because using viewmodel is not affected by lifecycle.

But the problem I have is that it seems to be initialized and saved every time because of the screen change.

Why is this?

ViewModel

class WriteRoutineViewModel : ViewModel() {
    private var _items: MutableLiveData<ArrayList<RoutineModel>> = MutableLiveData(arrayListOf())
    val items: LiveData<ArrayList<RoutineModel>> = _items

    fun addRoutine(workout: String) {
        val item = RoutineModel(workout, "TEST")

        item.setSubItemList(detailItem)
        _items.value?.add(item)
        _items.value = _items.value
    }
}

Fragment

class WriteRoutineFragment : Fragment() {
    private var _binding : FragmentWriteRoutineBinding? = null
    private val binding get() = _binding!!
    private lateinit var adapter : RoutineAdapter
    private val args : WriteRoutineFragmentArgs by navArgs()
    private val vm : WriteRoutineViewModel by viewModels { WriteRoutineViewModelFactory() }

    override fun onCreateView(inflater: LayoutInflater,
                              container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        _binding = FragmentWriteRoutineBinding.inflate(inflater, container, false)

        adapter = RoutineAdapter(::addDetail, ::deleteDetail)
        binding.rv.adapter = this.adapter
        return binding.root
    }

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

        args.workout?.let { workout ->
            vm.addRoutine(workout)
            Toast.makeText(context, workout, Toast.LENGTH_SHORT).show()
        }

        vm.items.observe(viewLifecycleOwner) { updatedItems ->
            adapter.setItems(updatedItems)
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}

UPDATE nav_graph

<fragment
        android:id="@+id/writeRoutine"
        android:name="com.example.lightweight.fragment.WriteRoutineFragment"
        android:label="fragment_write_routine"
        tools:layout="@layout/fragment_write_routine" >
        <action
            android:id="@+id/action_writeRoutineFragment_to_workoutListTabFragment"
            app:destination="@id/workoutListTabFragment" />
        <argument
            android:name="workout"
            app:argType="string"
            app:nullable="true"
            android:defaultValue="@null"/>
    </fragment>

Upvotes: 1

Views: 571

Answers (1)

Abhimanyu
Abhimanyu

Reputation: 14817

The view model should have an activity scope for the view model to be able to live throughout the activity lifecycle.

The view model must be initialized like this,

private val model: SharedViewModel by activityViewModels()

This exact use-case is explained in detail in the Android Docs

Upvotes: 2

Related Questions