如何在ViewModel中使用SearchView过滤LiveData<List<Note>>后通知观察者?

问题描述 投票:0回答:1

我有一个名为

Note
的实体,及其包含 SQL 特定逻辑的数据访问对象 (
NoteDAO
)。还有一个扩展
NoteDatabase
RoomDatabase
类和同时使用
NoteRepository
NoteDAO
NoteDatabase
NoteViewModel
通过NoteRepository与数据库交互。

在片段中,我使用

NoteViewModel
检索
onCreateView
中的所有笔记。观察这些注释后,我使用
RecyclerView
设置
adapter.submitList
项目。

但是,当合并

SearchView
时,我遇到了一个问题。虽然我可以从
SearchView
检索查询文本,但我尝试过滤底层
allNotes
(NoteViewModel 中类型为
LiveData<List<Note>>
的成员变量)并没有按预期通知观察者。

在了解了

MutableLiveData
LiveData
之间的区别后,我考虑将
allNotes
中的
NoteViewModel
成员更改为
MutableLiveData
。理论上,这应该允许我在
setValue
函数中使用
postValue
filterNotes(String searchTerm)
方法,从而通知观察者。但这不起作用 – 我什至无法使用
MutableLiveData
检索未过滤的笔记列表。

第一个片段

@Override
public View onCreateView(
        .......
) {
    ........

    RecyclerView recyclerView = binding.recyclerView;
    final NoteListAdapter adapter = new NoteListAdapter(new NoteListAdapter.WordDiff());
    recyclerView.setAdapter(adapter);
    recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));

    mNoteViewModel = new ViewModelProvider(requireActivity()).get(NoteViewModel.class);

    mNoteViewModel.getAllNotes().observe(getViewLifecycleOwner(), new Observer<List<Note>>() {
                @Override
                public void onChanged(List<Note> notes) {
                    Log.d("MainPage", "onChanged: " + notes);
                    adapter.submitList(notes);
                }
            });
   
    ........
}

NoteViewModel

public class NoteViewModel extends AndroidViewModel {

    private final NoteRepository mRepository;

    private final LiveData<List<Note>> mAllNotes;

    public NoteViewModel(@NonNull Application application) {
        super(application);
        mRepository = new NoteRepository(application);
        mAllNotes = mRepository.getAllNotes();
    }

    LiveData<List<Note>> getAllNotes() {
        return mAllNotes;
    }

    public void insert (Note note) { mRepository.insert(note); }
}

笔记存储库

public class NoteRepository {

    private final NoteDAO mNoteDAO;

    @NotNull
    private final LiveData<List<Note>> mAllNotes;

    NoteRepository(Application application) {
        NoteRoomDatabase db = NoteRoomDatabase.getDatabase(application);
        mNoteDAO = db.noteDAO();
        mAllNotes = mNoteDAO.getAllNotes();
    }

    public LiveData<List<Note>> getAllNotes() {
        return mAllNotes;
    }

    public void insert(Note note) {
        NoteRoomDatabase.databaseWriteExecutor.execute(() -> {
            mNoteDAO.insert(note);
        });
    }

}

NoteDAO

@Dao
public interface NoteDAO {

    @Insert
    void insert(Note note);

    @Query("SELECT * FROM notes ORDER BY id DESC")
    LiveData<List<Note>> getAllNotes();

    @Query("SELECT * FROM notes where title = :title ORDER BY id DESC")
    LiveData<List<Note>> getNotesByTitle(String title);

    @Query("SELECT * FROM notes where id = :id ORDER BY id DESC")
    LiveData<Note> getNoteById(long id);

    @Query("SELECT * FROM notes where color = :color ORDER BY id DESC")
    LiveData<List<Note>> getNotesByColor(String color);

}
java android android-recyclerview android-livedata mutablelivedata
1个回答
0
投票

我有两种方法

  1. 请使用 Kotlin flow 而不是 livedata。您可以使用强大的流量扩展功能来满足您的需求。这是一个例子
class NoteViewModel():AndroidViewModel{
 private val noteItemsFlow = combine(mAllNotes, searchQueryFlow){ items, query ->
        items.filter{
            it.noteName.contains(query) // Here you can write a logic to filter according to search query
        }
    }
}

// In Fragment
noteItemsFlow.collectLatest{
   adapter.submitList(it)
}
  1. 您可以在 Recycler 适配器中实现或扩展可过滤类并重写 getFilter 方法,这里是代码
class NoteListAdapter: RecyclerView.Adapter<RecyclerView.ViewHolder>(), Filterable {
    val notes = ArrayList<Note>()

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return NoteVieHolder()
    }

    override fun getItemCount(): Int {
        return notes.size
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        // Replace your onBindViewHolder code here
    }

    inner class NoteVieHolder: RecyclerView.ViewHolder(){
        // Replace your view holder code here
    }


    fun submitList(latestNotes:List<Note>){
        notes.clear()
        notes.addAll(latestNotes)
        notifyDataSetChanged()
    }

    override fun getFilter(): Filter {
        return  object : Filter() {
            override fun performFiltering(constraint: CharSequence?): FilterResults {
                val results = FilterResults()
                if (!constraint.isNullOrEmpty()){
                    val filterNotes = notes.filter { 
                        it.title.contains(constraint)
                    }
                    results.count = filterNotes.size
                    results.values = filterNotes
                }else{
                    results.count = notes.size
                    results.values = notes
                }
                
                return  results
            }

            override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
                if (results?.values != null) {
                    submitList(results.values as List<Note>)
                }
            }
        }
    }
}

希望这有帮助

© www.soinside.com 2019 - 2024. All rights reserved.