Closed lucamtudor closed 6 years ago
Same question as for pretty much any LiveData<PagedList<T>>
, which means there are two approaches and both should work: https://stackoverflow.com/questions/49192540/paging-library-filter-search
Haha, I didn't notice your stackoverflow answer 👍. I did something similar:
class MessagesViewModel : ViewModel() {
private val query = MutableLiveData<String?>()
fun dispatchQuery(query: String?) {
this.query.value = query
}
val messagesLiveData = switchMap(query) { queryText: String? ->
val realmDataSourceFactory = monarchy.createDataSourceFactory { realm ->
if (queryText.isNullOrEmpty()) {
realm.where(MessageListRealm::class.java)
} else {
realm.where(MessageListRealm::class.java)
.beginGroup()
.contains("fullName", queryText, Case.INSENSITIVE)
.or()
.contains("phoneMobile", queryText, Case.INSENSITIVE)
.endGroup()
}
}
val dataSourceFactory = realmDataSourceFactory.map { message ->
repoMessageListToModel(message)
}
monarchy.findAllPagedWithChanges(
realmDataSourceFactory,
LivePagedListBuilder(dataSourceFactory, PAGE_SIZE).setBoundaryCallback(mobiusBoundaryCallback)
)
}!!
}
Even though making a new factory each time doesn't feel right to me... Any feedback?
You should do realm.where<MessageListRealm>()
instead to preserve your sanity :p
But the other guy below was right. You could theoretically parameterize the data source factory with the query and it would pass it to the datasource on creation and it could be a mutable field instead of final.
I think it's currently final, but not set in stone. In fact it's quite easy to support.
The tricky part is if you actually use dataSourceFactory.map
I think if I let you redefine the query inside PagedLiveResults and invalidate, then it is as if you had gotten a background thread write. So you get new results.
I should do that. That's a good idea, thanks.
@Zhuinden thanks! I'm looking forward for the update ;)
Should be available as 0.3.1 and I hope that I can call invalidate()
from another thread :smile:
Try it out and report back when you can, although technically it should work
@Zhuinden me coding at midnight might be the problem, but I can't seem to make it work. can you crop up a quick sample with it?
AFAIK if you store the RealmDataSourceFactory<T>
in a field:
DataSource.Factory<Integer, RealmDog> realmDataSourceFactory = monarchy.createDataSourceFactory(
realm -> realm.where(RealmDog.class)); // as a field
Then you can call updateQuery((realm) -> { ... })
on it, which should replace the query in PagedLiveResults
, call invalidate
on the datasource, and therefore force the DataSource.Factory
to re-create the data source and provide new results without having to create a new LivePagedListBuilder and whatever.
I think multithreading foiled me again and I need to use AtomicReference. I'll fix this tomorrow.
Please try with 0.3.2
@Zhuinden I'll give it another try tonight. I've run into this while browsing the source code:
query.get().createQuery(realm).findAll(); // sort/distinct should be handled with new predicate type.
// paged results must be based on synchronous query!
Could you explain that?
You see none of that from the outside world, it just means that the RealmQuery that is executed on the Monarchy looper thread is always executed with findAll()
, and you can use Realm 5.x's realm.where<Blah>().sort("doh").distinct("meh")
to define the query, so now you don't have to worry about either findAllSortedAsync
or findAllSorted
or findAllAsync().distinct()
(which didn't even work :stuck_out_tongue: )
So the fact that they made sort + distinct be a property of the query itself is actually super-beneficial for the approach of Monarchy.
As for why it uses findAll()
instead of findAllAsync()
, it's because when I was making the predecessor of Paging integration in this repo, I was getting unexpected troubles with async queries. Can't really specify it more than that, but findAll
works and findAllAsync
did not work well in some cases sometimes.
Although in retrospect, findAllAsync
is needed for using the sync platform.
Anyways, this should work.
It's not working. I tested this with your example, what am I doing wrong?
public class PagedFragment
extends BaseFragment {
@BindView(R.id.recycler_view)
RecyclerView recyclerView;
@BindView(R.id.search_view)
SearchView searchView;
@Inject
Monarchy monarchy;
PagedDogAdapter pagedDogAdapter;
LiveData<PagedList<Dog>> dogs;
Monarchy.RealmDataSourceFactory<RealmDog> realmDataSourceFactory;
DataSource.Factory<Integer, Dog> dataSourceFactory;
Observer<PagedList<Dog>> observer = dogs -> {
pagedDogAdapter.submitList(dogs);
};
@Override
public void onAttach(Context context) {
super.onAttach(context);
CustomApplication.getInjector(context).inject(this);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_paged, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ButterKnife.bind(this, view);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
onQueryChanged(query);
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
onQueryChanged(newText);
return true;
}
});
pagedDogAdapter = new PagedDogAdapter();
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
recyclerView.setAdapter(pagedDogAdapter);
realmDataSourceFactory = monarchy.createDataSourceFactory(
realm -> realm.where(RealmDog.class), true);
dataSourceFactory = realmDataSourceFactory.map(input -> Dog.create(input.getName()));
dogs = monarchy.findAllPagedWithChanges(realmDataSourceFactory,
new LivePagedListBuilder<>(dataSourceFactory, 20));
dogs.observeForever(observer); // detach != destroy in fragments so this is manual
}
private void onQueryChanged(String query) {
if (realmDataSourceFactory != null) {
Log.d("tag", "query: " + query);
realmDataSourceFactory.updateQuery(realm -> realm.where(RealmDog.class).contains(RealmDogFields.NAME, query, Case.INSENSITIVE));
}
}
@Override
public void onDestroyView() {
dogs.removeObserver(observer);
super.onDestroyView();
}
}
@Zhuinden can you run a quick test yourself?
I will, but only later today.
@lucamtudor Sorry about "today" being such a remarkably vague time interval, but the good news is that I've fixed it and it's in 0.5.1 with https://github.com/Zhuinden/realm-monarchy/pull/24/commits/4737629778c997438404771da55d70f5d1f3bd1b
Now realmDataSourceFactory.updateQuery
works as intended.
So yeah, sorry for the delay, totally my mistake :disappointed_relieved:
This is more of a question, not a library issue per se.
I'm building a prototype to test monarchy & paging lib. Is there a quick pattern I can follow to filter a RealmDataSourceFactory backed paged list? I'm talking about a usual use-case with a long list of results & an edit-text based query.
Thanks for the great work on the library so far!