Лучшие практики использования области с видом ресайклера?
Есть ли у вас, ребята, какие-либо рекомендации по использованию сферы с помощью recyclerview?
Я знаю этот общий вопрос, но ничего не нашел в интернете. Например, я сталкиваюсь с множеством проблем, пытающихся реализовать простое изменение цвета в строке. Например, рассмотрим это типичное использование:
public class User extends RealmObject {
@PrimaryKey
String name;
boolean isSelected;
...
constructor, getter and setters
}
public class UserAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private RealmResults<User> users;
public UserAdapter(RealmResults<User> users) {
this.users = users;
}
...
public void markAsSelected(int position){
// get the old selected user and deselect it
notifyItemChanged(? how do i get the position given my User has no index ?);
// mark as selected the new user at position
}
У меня возникло множество проблем, так как я не мог найти что-либо в Интернете. Я знаю, это потому, что я не знаю, как правильно использовать сферу. Но найти правильный путь - это борьба сама по себе. Я прочитал всю их документацию, но безрезультатно.
EDIT: с тех пор, как меня попросили → Вместо того, чтобы сказать "у меня есть ряд проблем с [этим]", опишите свои проблемы, и мы постараемся представить идеи и ответы на ваши непонимания.
Итак, моя проблема проста:
У меня есть RealmUser:
public class RealmUser extends RealmObject {
@PrimaryKey
private String key;
private String name;
private boolean isSelected;
private boolean editMode;
private RealmList<RealmItemList> lists;
public RealmUser() {}
public RealmUser(String name, RealmList<RealmItemList> lists, boolean isSelected , boolean editMode) {
this.key = UUID.randomUUID().toString();
this.name = name;
this.isSelected = isSelected;
this.editMode = editMode;
if (lists ==null){
this.lists = new RealmList<RealmItemList>();
}else{
this.lists = lists;
}
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isSelected() {
return isSelected;
}
public void setSelected(boolean isSelected) {
this.isSelected = isSelected;
}
public boolean isEditMode() {
return editMode;
}
public void setEditMode(boolean editMode) {
this.editMode = editMode;
}
public RealmList<RealmItemList> getLists() {
return lists;
}
public void setLists(RealmList<RealmItemList> lists) {
this.lists = lists;
}
}
Который я ввел в массив RealmResults, используя:
RealmResults users = realm.where(RealmUser.class).findAll();
Я передаю свой пользовательский массив своему пользовательскому адаптеру:
public class UserAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private RealmResults<RealmUser> users;
public UserAdapter(RealmResults<RealmUser> users) {
this.users = users;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
if(viewType == 1){
View v = inflater.inflate(R.layout.detail_user, parent, false);
return new UserHolder(v);
}else if(viewType == 2){
View v = inflater.inflate(R.layout.edit_user, parent, false);
return new editUserHolder(v);
}else {
return null;
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
RealmUser user = users.get(position);
String userName = user.getName();
boolean isSelected = user.isSelected();
if (holder instanceof UserHolder ){
UserHolder uHolder = (UserHolder) holder;
uHolder.userText.setText(userName);
if (isSelected){
uHolder.userContainer.setBackgroundColor(Color.parseColor("#607D8B"));
}
}else if(holder instanceof editUserHolder){
editUserHolder eUserHolder = (editUserHolder) holder;
eUserHolder.userEditContainer.setBackgroundColor(Color.parseColor("#eeeeee"));
}
}
@Override
public int getItemViewType(int position) {
RealmUser user = users.get(position);
if (user.isEditMode()){
return 2;
}else {
return 1;
}
}
@Override
public int getItemCount() {
return users.size();
}
public void markAsSelected(int position, DrawerLayout mDrawerLayout , Toolbar toolbar, Realm realm){
// Here is my problem : How do I get the already selected user asuming there is one in my db and notify the UI that I changed that item.
}
У этого есть пользовательский кликер Listener: он получает элемент recyclerview, который был нажат, используя:
public class UserClickListener implements RecyclerView.OnItemTouchListener{
public static interface OnItemClickListener{
public void onItemClick(View v, int position);
}
private OnItemClickListener mListener;
private GestureDetector mGestureDetector;
public UserClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener)
{
mListener = listener;
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
View childView = recyclerView.findChildViewUnder(e.getX(), e.getY());
if(childView != null && mListener != null)
{
mListener.onItemClick(childView, recyclerView.getChildPosition(childView));
return true;
}
return false;
}
});
}
@Override
public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
View childView = view.findChildViewUnder(e.getX(), e.getY());
if(childView != null && mListener != null && mGestureDetector.onTouchEvent(e))
{
mListener.onItemClick(childView, view.getChildPosition(childView));
}
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
}
Что я добавляю в свой recyclerView с addOnItemTouchListener:
mListRecycler.addOnItemTouchListener(new UserClickListener(getActivity(), mListRecycler, new UserClickListener.OnItemClickListener(){
@Override
public void onItemClick(View view, int position)
{
UserAdapter myadapter = (UserAdapter) mListRecycler.getAdapter();
myadapter.markAsSelected(position, mDrawerLayout , mToolbar, realm);
}
}));
Ответы
Ответ 1
Для последних версий вы должны использовать RealmRecyclerViewAdapter в репозитории realm-android-adapters.
СТАРЫЙ ОТВЕТ ДЛЯ СТАРЫХ ВЕРСИЙ:
Я сделал это RealmRecyclerViewAdapter
на основе реализации RealmBaseAdapter
.
Это для v0.89.0 И ВЫШЕ
public abstract class RealmRecyclerViewAdapter<T extends RealmObject, VH extends RecyclerView.ViewHolder>
extends RecyclerView.Adapter<VH> { //put this in `io.realm`
protected LayoutInflater inflater;
protected OrderedRealmCollection<T> adapterData;
protected Context context;
private final RealmChangeListener listener;
public RealmRecyclerViewAdapter(Context context, OrderedRealmCollection<T> data) {
if (context == null) {
throw new IllegalArgumentException("Context cannot be null");
}
this.context = context;
this.adapterData = data;
this.inflater = LayoutInflater.from(context);
this.listener = new RealmChangeListener<RealmResults<T>>() {
@Override
public void onChange(RealmResults<T> results) {
notifyDataSetChanged();
}
};
if (data != null) {
addListener(data);
}
}
private void addListener(OrderedRealmCollection<T> data) {
if (data instanceof RealmResults) {
RealmResults realmResults = (RealmResults) data;
realmResults.addChangeListener(listener);
} else if (data instanceof RealmList) {
RealmList realmList = (RealmList) data;
realmList.realm.handlerController.addChangeListenerAsWeakReference(listener);
} else {
throw new IllegalArgumentException("RealmCollection not supported: " + data.getClass());
}
}
private void removeListener(OrderedRealmCollection<T> data) {
if (data instanceof RealmResults) {
RealmResults realmResults = (RealmResults) data;
realmResults.removeChangeListener(listener);
} else if (data instanceof RealmList) {
RealmList realmList = (RealmList) data;
realmList.realm.handlerController.removeWeakChangeListener(listener);
} else {
throw new IllegalArgumentException("RealmCollection not supported: " + data.getClass());
}
}
/**
* Returns how many items are in the data set.
*
* @return the number of items.
*/
@Override
public int getItemCount() {
if (adapterData == null) {
return 0;
}
return adapterData.size();
}
/**
* Get the data item associated with the specified position in the data set.
*
* @param position Position of the item whose data we want within the adapter's
* data set.
* @return The data at the specified position.
*/
public T getItem(int position) {
if (adapterData == null) {
return null;
}
return adapterData.get(position);
}
/**
* Get the row id associated with the specified position in the list. Note that item IDs are not stable so you
* cannot rely on the item ID being the same after {@link #notifyDataSetChanged()} or
* {@link #updateData(OrderedRealmCollection)} has been called.
*
* @param position The position of the item within the adapter data set whose row id we want.
* @return The id of the item at the specified position.
*/
@Override
public long getItemId(int position) {
// TODO: find better solution once we have unique IDs
return position;
}
/**
* Updates the data associated with the Adapter.
*
* Note that RealmResults and RealmLists are "live" views, so they will automatically be updated to reflect the
* latest changes. This will also trigger {@code notifyDataSetChanged()} to be called on the adapter.
*
* This method is therefore only useful if you want to display data based on a new query without replacing the
* adapter.
*
* @param data the new {@link OrderedRealmCollection} to display.
*/
public void updateData(OrderedRealmCollection<T> data) {
if (listener != null) {
if (adapterData != null) {
removeListener(adapterData);
}
if (data != null) {
addListener(data);
}
}
this.adapterData = data;
notifyDataSetChanged();
}
}
Это для v0.84.0 И ВЫШЕ, НО ПОСЛЕ ТОГО, что v0.89.0 (обновлено для v0.87.5):
public abstract class RealmRecyclerViewAdapter<T extends RealmObject, VH extends RecyclerView.ViewHolder>
extends RecyclerView.Adapter<VH> { //put this in `io.realm`
protected LayoutInflater inflater;
protected RealmResults<T> realmResults;
protected Context context;
private final RealmChangeListener listener;
public RealmRecyclerViewAdapter(Context context, RealmResults<T> realmResults, boolean automaticUpdate) {
if (context == null) {
throw new IllegalArgumentException("Context cannot be null");
}
this.context = context;
this.realmResults = realmResults;
this.inflater = LayoutInflater.from(context);
this.listener = (!automaticUpdate) ? null : new RealmChangeListener() {
@Override
public void onChange() {
notifyDataSetChanged();
}
};
if (listener != null && realmResults != null) {
realmResults.realm.handlerController.addChangeListenerAsWeakReference(listener);
}
}
/**
* Returns how many items are in the data set.
*
* @return count of items.
*/
@Override
public int getItemCount() {
if (realmResults == null) {
return 0;
}
return realmResults.size();
}
/**
* Returns the item associated with the specified position.
*
* @param i index of item whose data we want.
* @return the item at the specified position.
*/
public T getItem(int i) {
if (realmResults == null) {
return null;
}
return realmResults.get(i);
}
/**
* 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 {@link #notifyDataSetChanged()} or {@link #updateRealmResults(RealmResults)} has been called.
*
* @param i index of item in the adapter.
* @return current item ID.
*/
@Override
public long getItemId(int i) {
// TODO: find better solution once we have unique IDs
return i;
}
/**
* Updates the RealmResults 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 queryResults the new RealmResults coming from the new query.
*/
public void updateRealmResults(RealmResults<T> queryResults) {
if (listener != null) {
// Making sure that Adapter is refreshed correctly if new RealmResults come from another Realm
if (this.realmResults != null) {
this.realmResults.realm.removeChangeListener(listener);
}
if (queryResults != null) {
queryResults.realm.addChangeListener(listener);
}
}
this.realmResults = queryResults;
notifyDataSetChanged();
}
public void addChangeListenerAsWeakReference(RealmChangeListener realmChangeListener) {
if(realmResults != null) {
realmResults.realm.handlerController.addChangeListenerAsWeakReference(realmChangeListener);
}
}
}
Это для ПОСЛЕ ЧЕМ 0.84.0:
public abstract class RealmRecyclerViewAdapter<T extends RealmObject, VH extends RecyclerView.ViewHolder>
extends RecyclerView.Adapter<VH> { //put this in `io.realm`
protected LayoutInflater inflater;
protected RealmResults<T> realmResults;
protected Context context;
private final RealmChangeListener listener;
public RealmRecyclerViewAdapter(Context context, RealmResults<T> realmResults, boolean automaticUpdate) {
if(context == null) {
throw new IllegalArgumentException("Context cannot be null");
}
this.context = context;
this.realmResults = realmResults;
this.inflater = LayoutInflater.from(context);
this.listener = (!automaticUpdate) ? null : new RealmChangeListener() {
@Override
public void onChange() {
notifyDataSetChanged();
}
};
if(listener != null && realmResults != null) {
realmResults.getRealm()
.addChangeListener(listener);
}
}
@Override
public long getItemId(int i) {
// TODO: find better solution once we have unique IDs
return i;
}
public T getItem(int i) {
if(realmResults == null) {
return null;
}
return realmResults.get(i);
}
public void updateRealmResults(RealmResults<T> queryResults) {
if(listener != null) {
// Making sure that Adapter is refreshed correctly if new RealmResults come from another Realm
if(this.realmResults != null) {
realmResults.getRealm().removeChangeListener(listener);
}
if(queryResults != null) {
queryResults.getRealm().addChangeListener(listener);
}
}
this.realmResults = queryResults;
notifyDataSetChanged();
}
@Override
public int getItemCount() {
if(realmResults == null) {
return 0;
}
return realmResults.size();
}
}
Ответ 2
Некоторые из приведенных выше ответов включают отражение, не говоря уже о том, что секционированный RecyclerView может вызвать осложнения. Они также не поддерживают добавление и удаление элементов. Вот моя версия адаптера RecyclerView, которая работает с Realm, поддерживает секционированный RecyclerView, также добавляет и удаляет элементы в произвольных положениях, если это необходимо
Вот наш AbstractRealmAdapter, который заботится обо всех материалах низкого уровня, отображает заголовки, нижние колонтитулы, элементы, загружает данные внутри RealmResults, управляет типами элементов
import io.realm.Realm;
import io.realm.RealmObject;
import io.realm.RealmResults;
public abstract class AbstractRealmAdapter<T extends RealmObject, VH extends RecyclerView.ViewHolder>
extends RecyclerView.Adapter<VH> {
public static final int HEADER_COUNT = 1;
public static final int FOOTER_COUNT = 1;
//Our data source
protected RealmResults<T> mResults;
public AbstractRealmAdapter(Realm realm) {
//load data from subclasses
mResults = loadData(realm);
notifyDataSetChanged();
}
public int getHeaderCount() {
return hasHeader() ? HEADER_COUNT : 0;
}
public int getFooterCount() {
return hasFooter() ? FOOTER_COUNT : 0;
}
public boolean isHeader(int position) {
if (hasHeader()) {
return position < HEADER_COUNT;
} else {
return false;
}
}
public boolean isFooter(int position) {
if (hasFooter()) {
return position >= getCount() + getHeaderCount();
} else {
return false;
}
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public final int getItemViewType(int position) {
if (isHeader(position)) {
return ItemType.HEADER.ordinal();
} else if (isFooter(position)) {
return ItemType.FOOTER.ordinal();
} else {
return ItemType.ITEM.ordinal();
}
}
/**
* @param position the position within our adapter inclusive of headers,items and footers
* @return an item only if it is not a header or a footer, otherwise returns null
*/
public T getItem(int position) {
if (!isHeader(position) && !isFooter(position) && !mResults.isEmpty()) {
return mResults.get(position - getHeaderCount());
}
return null;
}
@Override
public final int getItemCount() {
return getHeaderCount() + getCount() + getFooterCount();
}
public final int getCount() {
return mResults.size();
}
public abstract boolean hasHeader();
public abstract boolean hasFooter();
public void setData(RealmResults<T> results) {
mResults = results;
notifyDataSetChanged();
}
protected abstract RealmResults<T> loadData(Realm realm);
public enum ItemType {
HEADER, ITEM, FOOTER;
}
}
Чтобы добавить элементы некоторым способом или удалить элементы путем удаления, у нас есть расширение в виде AbstractMutableRealmAdapter, которое выглядит как показано ниже.
import android.support.v7.widget.RecyclerView;
import io.realm.Realm;
import io.realm.RealmObject;
public abstract class AbstractMutableRealmAdapter<T extends RealmObject, VH extends RecyclerView.ViewHolder>
extends AbstractRealmAdapter<T, VH> implements OnSwipeListener {
private Realm realm;
public AbstractMutableRealmAdapter(Realm realm) {
//call the superclass constructor to load data from subclasses into realmresults
super(realm);
this.realm = realm;
}
public void add(T item, boolean update) {
realm.beginTransaction();
T phraseToWrite = (update == true) ? realm.copyToRealmOrUpdate(item) : realm.copyToRealm(item);
realm.commitTransaction();
notifyItemRangeChanged(0, mResults.size());
}
@Override
public final void onSwipe(int position) {
if (!isHeader(position) && !isFooter(position) && !mResults.isEmpty()) {
int itemPosition = position - getHeaderCount();
realm.beginTransaction();
T item = mResults.get(itemPosition);
item.removeFromRealm();
realm.commitTransaction();
notifyItemRemoved(position);
}
}
}
Обратите внимание на использование интерфейса OnSwipeListener, который выглядит так:
public interface OnSwipeListener {
/**
* @param position the position of the item that was swiped within the RecyclerView
*/
void onSwipe(int position);
}
Этот SwipeListener используется для выполнения Swipe для удаления внутри нашего TouchHelperCallback, который, в свою очередь, используется для прямого удаления объектов из Realm и выглядит следующим образом
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
public class TouchHelperCallback extends ItemTouchHelper.Callback {
private final OnSwipeListener mSwipeListener;
public TouchHelperCallback(OnSwipeListener adapter) {
mSwipeListener = adapter;
}
/**
* @return false if you dont want to enable drag else return true
*/
@Override
public boolean isLongPressDragEnabled() {
return false;
}
/**
* @return true of you want to enable swipe in your RecyclerView else return false
*/
@Override
public boolean isItemViewSwipeEnabled() {
return true;
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
//We want to let the person swipe to the right on devices that run LTR and let the person swipe from right to left on devices that run RTL
int swipeFlags = ItemTouchHelper.END;
return makeMovementFlags(0, swipeFlags);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
RecyclerView.ViewHolder target) {
return false;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
mSwipeListener.onSwipe(viewHolder.getAdapterPosition());
}
}
Полная демонстрация реализации доступна здесь для просмотра https://github.com/slidenerd/SpamWordList/tree/spamphraser_with_realmresults_base Не стесняйтесь предлагать какие-либо улучшения
Я заменил методы notifyXXX объектами notifyDataSetChanged, RealmResults являются живыми объектами, что означает, что они автоматически изменяются при обновлении данных, я пытался использовать методы notifyXXX, и они вызвали исключение несогласованности RecyclerView. Мне хорошо известно, что notifyDataSetChanged ( ) будет возиться с анимацией, будет держать вас, ребята, обновлены на решении, которое преодолевает ошибку несогласованности и в то же время обеспечивает хороший опыт адаптера
Ответ 3
Теперь, когда в Realm 0.88.2 мы можем сделать адаптер RecyclerView, который обновляет RecyclerView с большей точностью, чем использование notifyDataSetChanged() каждый раз. Это можно сделать, используя новую возможность создания пользовательских методов.
Переопределение метода equals, в объекте realm, который будет использоваться с адаптером recycler, - все, что потребуется. (На самом деле вам не нужно переопределять равные... но вы можете обнаружить, что объекты сферы не совпадают друг с другом, когда вы их ожидаете. Это приведет к ненужным обновлениям recyclerview после запуска diff)
Затем добавьте Google java-diff-utils к вашим зависимостям gradle
compile 'com.googlecode.java-diff-utils:diffutils:1.3.0'
Используя эту реализацию RealmRecyclerViewAdapter, копия realmResults выполняется при запуске и при каждом изменении для сравнения с будущими изменениями. Обнаруженные изменения используются для обновления RecyclerView по мере необходимости
public abstract class RealmRecyclerViewAdapter<T extends RealmObject, VH extends RecyclerView.ViewHolder>
extends RecyclerView.Adapter<VH> {
protected RealmResults<T> realmResults;
protected List<T> lastCopyOfRealmResults;
int maxDepth = 0;
private RealmChangeListener realmResultsListener;
Realm realm;
public RealmRecyclerViewAdapter(RealmResults<T> realmResults, boolean automaticUpdate) {
this(realmResults, automaticUpdate, 0);
}
/**
*
* @param realmResults
* @param automaticUpdate
* @param maxDepth limit of the deep copy when copying realmResults. All references after this depth will be {@code null}. Starting depth is {@code 0}.
* A copy of realmResults is made at start, and on every change to compare against future changes. Detected changes are used to update
* the RecyclerView as appropriate
*/
public RealmRecyclerViewAdapter(RealmResults<T> realmResults, boolean automaticUpdate, int maxDepth) {
this.realmResultsListener = (!automaticUpdate) ? null : getRealmResultsChangeListener();
if (realmResultsListener != null && realmResults != null) {
realmResults.addChangeListener(realmResultsListener);
}
this.realmResults = realmResults;
realm = Realm.getDefaultInstance();
this.maxDepth = maxDepth;
lastCopyOfRealmResults = realm.copyFromRealm(realmResults, this.maxDepth);
}
@Override
public int getItemCount() {
return realmResults != null ? realmResults.size() : 0;
}
/**
* Make sure this is called before a view is destroyed to avoid memory leaks do to the listeners.
* Do this by calling setAdapter(null) on your RecyclerView
* @param recyclerView
*/
@Override
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
super.onDetachedFromRecyclerView(recyclerView);
if (realmResultsListener != null) {
if (realmResults != null) {
realmResults.removeChangeListener(realmResultsListener);
}
}
realm.close();
}
/**
* Update the RealmResults associated with the Adapter. Useful when the query has been changed.
* If the query does not change you might consider using the automaticUpdate feature.
*
* @param queryResults the new RealmResults coming from the new query.
* @param maxDepth limit of the deep copy when copying realmResults. All references after this depth will be {@code null}. Starting depth is {@code 0}.
* A copy of realmResults is made at start, and on every change to compare against future changes. Detected changes are used to update
* the RecyclerView as appropriate
*/
public void updateRealmResults(RealmResults<T> queryResults, int maxDepth) {
if (realmResultsListener != null) {
if (realmResults != null) {
realmResults.removeChangeListener(realmResultsListener);
}
}
realmResults = queryResults;
if (realmResults != null && realmResultsListener !=null) {
realmResults.addChangeListener(realmResultsListener);
}
this.maxDepth = maxDepth;
lastCopyOfRealmResults = realm.copyFromRealm(realmResults,this.maxDepth);
notifyDataSetChanged();
}
public T getItem(int position) {
return realmResults.get(position);
}
public int getRealmResultsSize(){
return realmResults.size();
}
private RealmChangeListener getRealmResultsChangeListener() {
return new RealmChangeListener<RealmResults<T>>() {
@Override
public void onChange(RealmResults<T> element) {
if (lastCopyOfRealmResults != null && !lastCopyOfRealmResults.isEmpty()) {
if (realmResults.isEmpty()) {
// If the list is now empty, just notify the recyclerView of the change.
lastCopyOfRealmResults = realm.copyFromRealm(realmResults,maxDepth);
notifyDataSetChanged();
return;
}
Patch patch = DiffUtils.diff(lastCopyOfRealmResults, realmResults);
List<Delta> deltas = patch.getDeltas();
lastCopyOfRealmResults = realm.copyFromRealm(realmResults,maxDepth);
if (!deltas.isEmpty()) {
List<Delta> deleteDeltas = new ArrayList<>();
List<Delta> insertDeltas = new ArrayList<>();
for (final Delta delta : deltas) {
switch (delta.getType()){
case DELETE:
deleteDeltas.add(delta);
break;
case INSERT:
insertDeltas.add(delta);
break;
case CHANGE:
notifyItemRangeChanged(
delta.getRevised().getPosition(),
delta.getRevised().size());
break;
}
}
for (final Delta delta : deleteDeltas) {
notifyItemRangeRemoved(
delta.getOriginal().getPosition(),
delta.getOriginal().size());
}
//item should be removed before insertions are performed
for (final Delta delta : insertDeltas) {
notifyItemRangeInserted(
delta.getRevised().getPosition(),
delta.getRevised().size());
}
}
} else {
notifyDataSetChanged();
lastCopyOfRealmResults = realm.copyFromRealm(realmResults,maxDepth);
}
}
};
}
}
Ответ 4
В вашем сообщении нет даже реального вопроса.
Вы проверили это сообщение: http://gradlewhy.ghost.io/realm-results-with-recyclerview/?
Не уверен, почему вы не просто используете ArrayList в своем адаптере и добавите все элементы из RealmResult в этот список. Может ли кто-нибудь объяснить, почему решение в блоге лучше?
Ответ 5
Реализация надстройки Realm от Thorben Primke - очень удобный метод
для обработки приложений Recycler View с базами данных Realm. Его github содержит хорошие примеры способов его реализации.
Я включу здесь, чтобы у вас был пример. Сначала измените проектную сборку gradle для jitpack.io:
allprojects {
repositories {
jcenter()
maven { url "https://jitpack.io" }
}
Затем ваш модуль gradle указывает на библиотеку: (обратите внимание, проверьте последнюю версию)
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.github.thorbenprimke:realm-recyclerview:0.9.20'
Создайте макет xml для просмотра ресайклеров с помощью RealmRecyclerView:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<co.moonmonkeylabs.realmrecyclerview.RealmRecyclerView
android:id="@+id/realm_recycle_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:rrvIsRefreshable="true"
app:rrvEmptyLayoutId="@layout/empty_view"
app:rrvLayoutType="LinearLayout"
app:rrvSwipeToDelete="true"
/>
</RelativeLayout>
Теперь в вашем фрагменте RealmRecycler получите результат запроса RealmObjects Realm, раздуйте и определите PrimkAdmAdapter Adapter:
Log.i(TAG, " Obtain Filtered List");
final RealmResults <Session> realmResults = queryD.findAllSorted(
"sessionId", Sort.DESCENDING);
Log.i(TAG, " Inflate realm List");
View view = inflater.inflate(R.layout.realm_card_recycler2, null);
Log.i(TAG, " Define and configure SessionRealmAdapter");
SessionRealmAdapter sessionRealmAdapter =
new SessionRealmAdapter(getActivity(), realmResults, true, true);`enter code here`
RealmRecyclerView realmRecyclerView =
(RealmRecyclerView) view.findViewById(R.id.realm_recycle_view);
realmRecyclerView.setAdapter(sessionRealmAdapter);
Наконец, настройте адаптер Realm для любых действий. У меня есть пара для кликов, и для удаления записей в реальном времени вы удалили салфетки.
public class SessionRealmAdapter
extends RealmBasedRecyclerViewAdapter<Session, SessionRealmAdapter.ViewHolder> {
public class ViewHolder extends RealmViewHolder {
public TextView sessionTextView;
public ViewHolder(FrameLayout container) {
super(container);
this.sessionTextView = (TextView) container.findViewById(R.id.session_text_view);
}
}
public SessionRealmAdapter(
Context context,
RealmResults<Session> realmResults,
boolean automaticUpdate,
boolean animateResults) {
super(context, realmResults, automaticUpdate, animateResults);
}
@Override
public ViewHolder onCreateRealmViewHolder(ViewGroup viewGroup, int viewType) {
View v = inflater.inflate(R.layout.session_simple_view, viewGroup, false);
return new ViewHolder((FrameLayout) v);
}
@Override
public void onBindRealmViewHolder(ViewHolder viewHolder, int position) {
final Session singleSession = realmResults.get(position);
viewHolder.sessionTextView.setText(singleSession.gettMethod());
viewHolder.sessionTextView.setOnClickListener(
new View.OnClickListener(){
@Override
public void onClick(View v){
selectSession(singleSession);
showMessage(" Selected "+singleSession.gettMethod());
}
}
);
viewHolder.sessionTextView.setOnLongClickListener(
new View.OnLongClickListener(){
@Override
public boolean onLongClick(View v){
showInformationDialog(singleSession);
showMessage("Long click selected for "
+singleSession.getSessionTitle());
return true;
}
}
);
}
}