I have Implemented my new project with Realm Database Plugin
.
I have a functionality of Pagination
with Number of Record as 20.
So How can I fetch 20 Record using Realm Query .
I searched, but did not get any solution.
问题:
回答1:
I wrote an article on Realm where I specifically mention that
Common mistake: attempting to paginate a
RealmResults<T>
or “limit the number of results in it” for no valid reason whatsoever
I’ve seen people on SO attempting to paginate a RealmResults, or “how do I do a limit query”. The first question asked is why are you even trying to do that. Mostly because to limit a RealmResults, you simply have to not index it above your arbitrary threshold.
To make it clear: RealmResults does NOT contain any elements. It contains the means to evaluate the results of the query. The element is obtained from the Realm only when you call realmResults.get(i), and only that single element is returned at a time. It’s like a Cursor, except it’s a List. Therefore, “limiting” it and “paginating” it doesn’t make sense. If you really need it, then limit your index.
So if you really need pagination, then write an adapter that receives a RealmResults
, keeps track of the current page, shows
int pageSize = results.size() - pageIndex*20;
if(pageSize < 0) {
pageSize = 0;
}
pageSize = Math.min(pageSize, 20);
elements in getItemCount()
, and displays elements from [20*pageIndex + 0...19]
from your results.
When you write your adapter, don't forget to add/remove a change listener kept in a field variable to your results which calls notifyDataSetChanged()
.
So, like,
/*
* Copyright 2016 Realm Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.realm;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
/**
* The RealmPagedRecyclerViewAdapter class is an abstract utility class for binding RecyclerView UI elements to Realm data.
* <p>
* This adapter will automatically handle any updates to its data and call notifyDataSetChanged() as appropriate.
* Currently there is no support for RecyclerView's data callback methods like notifyItemInserted(int), notifyItemRemoved(int),
* notifyItemChanged(int) etc.
* It means that, there is no possibility to use default data animations.
* <p>
* The RealmAdapter will stop receiving updates if the Realm instance providing the {@link OrderedRealmCollection} is
* closed.
*
* @param <T> type of {@link RealmModel} stored in the adapter.
* @param <VH> type of RecyclerView.ViewHolder used in the adapter.
*/
public abstract class RealmPagedRecyclerViewAdapter<T extends RealmModel, VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {
protected final LayoutInflater inflater;
@NonNull
protected final Context context;
private final boolean hasAutoUpdates;
private final RealmChangeListener listener;
@Nullable
private OrderedRealmCollection<T> adapterData;
private int pageIndex = 0;
public RealmRecyclerViewAdapter(@NonNull Context context, @Nullable OrderedRealmCollection<T> data, boolean autoUpdate) {
//noinspection ConstantConditions
if (context == null) {
throw new IllegalArgumentException("Context can not be null");
}
this.context = context;
this.adapterData = data;
this.inflater = LayoutInflater.from(context);
this.hasAutoUpdates = autoUpdate;
// Right now don't use generics, since we need maintain two different
// types of listeners until RealmList is properly supported.
// See https://github.com/realm/realm-java/issues/989
this.listener = hasAutoUpdates ? new RealmChangeListener() {
@Override
public void onChange(Object results) {
notifyDataSetChanged();
}
} : null;
}
public void updatePage(int index) {
this.pageIndex = index;
notifyDataSetChanged();
}
@Override
public void onAttachedToRecyclerView(final RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
if (hasAutoUpdates && isDataValid()) {
//noinspection ConstantConditions
addListener(adapterData);
}
}
@Override
public void onDetachedFromRecyclerView(final RecyclerView recyclerView) {
super.onDetachedFromRecyclerView(recyclerView);
if (hasAutoUpdates && isDataValid()) {
//noinspection ConstantConditions
removeListener(adapterData);
}
}
/**
* Returns the current ID for an item. Note that item IDs are not stable so you cannot rely on the item ID being the
* same after notifyDataSetChanged() or {@link #updateData(OrderedRealmCollection)} has been called.
*
* @param index position of item in the adapter.
* @return current item ID.
*/
@Override
public long getItemId(final int index) {
return index;
}
@Override
public int getItemCount() {
if(!isDataValid()) {
return 0;
}
int pageSize = results.size() - pageIndex*20;
if(pageSize < 0) {
pageSize = 0;
}
pageSize = Math.min(pageSize, 20);
return pageSize;
}
/**
* Returns the item associated with the specified position.
* Can return {@code null} if provided Realm instance by {@link OrderedRealmCollection} is closed.
*
* @param index index of the item.
* @return the item at the specified position, {@code null} if adapter data is not valid.
*/
@Nullable
public T getItem(int index) {
//noinspection ConstantConditions
if(!isDataValid()) {
return null;
}
return adapterData.get(index + 20*pageIndex) : null;
}
/**
* Returns data associated with this adapter.
*
* @return adapter data.
*/
@Nullable
public OrderedRealmCollection<T> getData() {
return adapterData;
}
/**
* Updates the data associated to the Adapter. Useful when the query has been changed.
* If the query does not change you might consider using the automaticUpdate feature.
*
* @param data the new {@link OrderedRealmCollection} to display.
*/
public void updateData(@Nullable OrderedRealmCollection<T> data) {
if (hasAutoUpdates) {
if (adapterData != null) {
removeListener(adapterData);
}
if (data != null) {
addListener(data);
}
}
this.adapterData = data;
notifyDataSetChanged();
}
private void addListener(@NonNull OrderedRealmCollection<T> data) {
if (data instanceof RealmResults) {
RealmResults realmResults = (RealmResults) data;
//noinspection unchecked
realmResults.addChangeListener(listener);
} else if (data instanceof RealmList) {
RealmList realmList = (RealmList) data;
//noinspection unchecked
realmList.realm.handlerController.addChangeListenerAsWeakReference(listener);
} else {
throw new IllegalArgumentException("RealmCollection not supported: " + data.getClass());
}
}
private void removeListener(@NonNull OrderedRealmCollection<T> data) {
if (data instanceof RealmResults) {
RealmResults realmResults = (RealmResults) data;
realmResults.removeChangeListener(listener);
} else if (data instanceof RealmList) {
RealmList realmList = (RealmList) data;
//noinspection unchecked
realmList.realm.handlerController.removeWeakChangeListener(listener);
} else {
throw new IllegalArgumentException("RealmCollection not supported: " + data.getClass());
}
}
private boolean isDataValid() {
return adapterData != null && adapterData.isValid();
}
}
This should do it for Realm 1.2.0, although I haven't tested it.