[通过观察ViewModel在RecyclerView中搜索PagedList的实时数据

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

使用android Paging库,从块中加载数据库中的数据真的很容易,ViewModel提供了自动UI更新和数据保留。所有这些框架模块都可以帮助我们在android平台上创建出色的应用。

[典型的android应用必须显示项目列表,并允许用户搜索该列表。这就是我想通过我的应用程序实现的目标。因此,我通过阅读许多文档,教程甚至stackoverflow答案来完成实现。 但是我不确定我是正确执行还是应该执行该操作。因此,在下面,我展示了使用ViewModel和RecyclerView实现分页库的方式。

[请检查我的实现并纠正我的错误之处,或者告诉我应该怎么做。我认为有很多像我这样的新android开发人员仍对如何正确执行感到困惑,因为没有单一来源可以回答您有关此类实现的所有问题。

我只展示我认为重要的内容。我正在使用Room。这是我正在使用的实体。

@Entity(tableName = "event")
public class Event {
    @PrimaryKey(autoGenerate = true)
    public int id;

    public String title;
}

这里是事件实体的DAO。

@Dao
public interface EventDao {
    @Query("SELECT * FROM event WHERE event.title LIKE :searchTerm")
    DataSource.Factory<Integer, Event> getFilteredEvent(String searchTerm);
}

这里是ViewModel扩展了AndroidViewModel,它允许通过根据搜索文本提供所有事件或已过滤事件的LiveData >来进行读取和搜索。 我真的很困惑,每当filterEvent发生变化时,我都会创建新的LiveData,它可能是多余的,也可能是错误的。

private MutableLiveData<Event> filterEvent = new MutableLiveData<>();
private LiveData<PagedList<Event>> data;

private MeDB meDB;

public EventViewModel(Application application) {
    super(application);
    meDB = MeDB.getInstance(application);

    data = Transformations.switchMap(filterEvent, new Function<Event, LiveData<PagedList<Event>>>() {
        @Override
        public LiveData<PagedList<Event>> apply(Event event) {
            if (event == null) {
                // get all the events
                return new LivePagedListBuilder<>(meDB.getEventDao().getAllEvent(), 5).build();
            } else {
                // get events that match the title
                return new LivePagedListBuilder<>(meDB.getEventDao()
                          .getFilteredEvent("%" + event.title + "%"), 5).build();
            }
        }
    });
}

public LiveData<PagedList<Event>> getEvent(Event event) {
    filterEvent.setValue(event);
    return data;
}

对于搜索事件,我正在使用SearchView。在onQueryTextChange中,我编写了以下代码来搜索或显示没有提供搜索词的所有事件,这意味着搜索已完成或被取消。

Event dumpEvent;

@Override
public boolean onQueryTextChange(String newText) {

    if (newText.equals("") || newText.length() == 0) {
        // show all the events
        viewModel.getEvent(null).observe(this, events -> adapter.submitList(events));
    }

    // don't create more than one object of event; reuse it every time this methods gets called
    if (dumpEvent == null) {
        dumpEvent = new Event(newText, "", -1, -1);
    }

    dumpEvent.title = newText;

    // get event that match search terms
    viewModel.getEvent(dumpEvent).observe(this, events -> adapter.submitList(events));

    return true;
}
android android-recyclerview searchview android-viewmodel android-paging
1个回答
0
投票

我将强烈建议您开始使用RxJava,它可以简化整个搜索逻辑的问题。

我建议在Dao Room Class中实现两种方法,一种是在搜索为空时查询所有数据,另一种是按照以下方式查询搜索到的项目。数据源用于在页面列表中加载数据

 @Query("SELECT * FROM food order by food_name")
 DataSource.Factory<Integer, Food> loadAllFood();

@Query("SELECT * FROM food where food_name LIKE  :name order by food_name")
DataSource.Factory<Integer, Food> loadAllFoodFromSearch(String name);

在ViewModel类中,我们需要两个参数,其中一个将用于观察搜索到的文本,而我们使用MutableLiveData来在OnChange期间通知视图。然后LiveData观察Items列表并更新UI。SwitchMap应用接受输入LiveData并生成相应LiveData输出的功能。请找到下面的代码

public LiveData<PagedList<Food>> listAllFood;
public MutableLiveData<String> filterFoodName = new MutableLiveData<>();

public void initialFood(final FoodDao foodDao) {
    this.foodDao = foodDao;

    PagedList.Config config = (new PagedList.Config.Builder())
            .setPageSize(10)
            .build();

    listAllFood = Transformations.switchMap(filterFoodName, outputLive -> {

               if (outputLive == null || outputLive.equals("") || input.equals("%%")) {
                //check if the current value is empty load all data else search
                return new LivePagedListBuilder<>(
                        foodDao.loadAllFood(), config)
                        .build();
            } else {
                   return new LivePagedListBuilder<>(
                        foodDao.loadAllFoodFromSearch(input),config)
                        .build();
            }
        });
    }

viewModel然后将LiveData传播到视图,并观察数据的变化。然后在MainActivity中调用将使用SwitchMap函数的initialFood方法。

  viewModel = ViewModelProviders.of(this).get(FoodViewModel.class);
  viewModel.initialFood(FoodDatabase.getINSTANCE(this).foodDao());

  viewModel.listAllFood.observe(this, foodlistPaging -> {
        try {
     Log.d(LOG_TAG, "list of all page number " + foodlistPaging.size());

            foodsactivity = foodlistPaging;
            adapter.submitList(foodlistPaging);

        } catch (Exception e) {
        }
    });

  recyclerView.setAdapter(adapter);

对于第一个onCreate,将filterFoodName初始化为Null,以便检索所有项目。viewModel.filterFoodName.setValue(“”);

然后将TextChangeListener应用于EditText并调用MutableLiveData,它将观察更改并使用搜索到的Item更新UI。

searchFood.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, 
int i1, int i2) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int 
 i1, int i2) {

            }

            @Override
            public void afterTextChanged(Editable editable) {
                //just set the current value to search.
                viewModel.filterFoodName.
                        setValue("%" + editable.toString() + "%");
            }
        });
    }

下面是我的完整代码的github回购。

https://github.com/muchbeer/PagingSearchFood

希望有帮助


-1
投票

显然,你是对的。使用前先了解MVVM时。这里是图像和sourceThe ViewModel

当然,您可以使用'androidx.lifecycle:lifecycle-extensions:2.0.0'方便地创建视图模型。

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