简体   繁体   中英

Room livedata , databinding issue : UI doesn't update when data changes

I am now developing an application where I use MVVM pattern for UI and repository interaction. In other words, I receive live data object with a list of models from my ROOM data base query via repository, then assign it to my live data variable in viewmodel. After that, this data should be populated to my xml layout recycler view via data binding, but It happens only once fragment is initialised. In other cases recycler view is void

DAO code :

@Query("SELECT * FROM note WHERE content LIKE :query ORDER BY isStarred")
    fun searchAllNotes(query : String?) : Flow<List<Note>>

ViewModel code:

@HiltViewModel
class HomeViewModel @Inject constructor (
    private val noteRepository : NoteRepository
) : ViewModel() {


    private var _notesLiveData : LiveData<List<Note>> = noteRepository.getAllNotes().asLiveData()
    val notesLiveData  get()= _notesLiveData



    fun searchNotes(query : String){
        viewModelScope.launch(Dispatchers.IO){
            _notesLiveData = noteRepository.searchAllNotes(query).asLiveData()
        }
    }

    fun deleteNote(note : Note){
        viewModelScope.launch(Dispatchers.IO){
            noteRepository.deleteNote(note)
        }
    }

    fun updateNoteChecked(note : Note){
        viewModelScope.launch(Dispatchers.IO){
            noteRepository.updateNoteChecked(note.id, note.isStarred)
        }
    }

Fragment code

@AndroidEntryPoint
class HomeFragment : Fragment(),
NoteCardAdapter.NoteTouchListener,
SearchView.OnQueryTextListener{

    private var _binding : FragmentHomeBinding? = null
    val binding get() = _binding!!

    private val adapter by lazy {
        NoteCardAdapter(this as NoteCardAdapter.NoteTouchListener)
    }

    private val vm : HomeViewModel by viewModels()

    private val noteSharedViewModel : NoteSharedViewModel by activityViewModels()

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentHomeBinding.inflate(inflater)
        return binding.root
    }


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

        binding.adapter = adapter
        binding.vm = vm

        binding.apply {
            lifecycleOwner = viewLifecycleOwner
            homeRecyclerView.isNestedScrollingEnabled = false
            homeRecyclerView.layoutManager = LinearLayoutManager(view.context)
            homeRecyclerView.itemAnimator= NotesItemAnimator()
        }
        binding.homeSearchView.isSubmitButtonEnabled  = true
        binding.homeSearchView.setOnQueryTextListener(this as SearchView.OnQueryTextListener)

        binding.addNoteButton.setOnClickListener{
            val note = Note(
                "","","",false, activity?.getDate(), folderId = -1
            )
            noteSharedViewModel.selectNote(note)
            val action = HomeFragmentDirections.actionHomeFragmentToSingleNoteFragment(
                isNew = true
            )

            findNavController().navigate(action)
        }

        binding.foldersButton.setOnClickListener{
            findNavController().navigate(HomeFragmentDirections.actionHomeFragmentToFoldersFragment())
        }
    }

xml layout code :

<?xml version="1.0" encoding="utf-8"?>

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    >
    
    <data>
        <variable
            name="vm"
            type="com.example.leonidsnotesapplication.presentation.notes_feature.viewmodels.HomeViewModel" />

        <variable
            name="adapter"
            type="com.example.leonidsnotesapplication.presentation.notes_feature.adapters.NoteCardAdapter" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:background="@color/note_background_color_3"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".presentation.notes_feature.fragments.HomeFragment">

        <androidx.appcompat.widget.SearchView
            android:id="@+id/homeSearchView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:theme="@style/AppSearchView"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"/>

        <TextView
            android:id="@+id/tvRecentTitle"
            android:textStyle="bold"
            android:textSize="25sp"
            android:textColor="@color/button_color_2"
            android:text="@string/recent"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:layout_marginStart="20dp"
            app:layout_constraintTop_toBottomOf="@id/homeSearchView"
            app:layout_constraintStart_toStartOf="parent"/>

        <ImageView
            android:layout_width="24dp"
            android:layout_height="24dp"
            android:layout_marginStart="16dp"
            android:layout_marginTop="28dp"
            android:background="@drawable/ic_circle_arrow"
            app:layout_constraintStart_toEndOf="@id/tvRecentTitle"
            app:layout_constraintTop_toBottomOf="@id/homeSearchView" />

        <androidx.recyclerview.widget.RecyclerView
            tools:listitem="@layout/note_card_view"
            android:scrollbars="vertical"
            android:scrollbarStyle="outsideInset"
            android:id="@+id/homeRecyclerView"
            android:layout_width="match_parent"
            android:requiresFadingEdge="vertical"
            android:fadingEdge="vertical"
            android:fadingEdgeLength="15dp"
            android:layout_height="500dp"
            android:layout_marginTop="30dp"
            app:setNoteAdapter="@{adapter}"
            app:submitNoteList="@{vm.notesLiveData}"
            app:layout_constraintTop_toBottomOf="@id/tvRecentTitle"
            app:layout_constraintStart_toStartOf="parent"
            />

        <com.google.android.material.floatingactionbutton.FloatingActionButton
            android:backgroundTint="@color/button_color_1"
            android:id="@+id/add_note_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="16dp"
            android:src="@drawable/ic_create"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent" />

        <com.google.android.material.floatingactionbutton.FloatingActionButton
            android:backgroundTint="@color/button_color_1"
            android:id="@+id/folders_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="16dp"
            android:src="@drawable/ic_folders_stack"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent" />


    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

Data binding adapter :

@BindingAdapter("submitNoteList")
fun submitNoteList(recyclerView: RecyclerView, data : List<Note>?){
    val adapter = recyclerView.adapter as NoteCardAdapter
    adapter.setData((data as ArrayList<Note>? ?: arrayListOf()))
}

@BindingAdapter("setNoteAdapter")
fun setNoteAdapter(recyclerView: RecyclerView, adapter: NoteCardAdapter){
    adapter.let {
        recyclerView.adapter = it
    }
}

You should observe your live data. Example code is: vm.notesLiveData.observe(viewLifecycleOwner) { adapter.submitList(it) }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM