web-dev-qa-db-fra.com

Les meilleures pratiques pour utiliser le royaume avec une vue recycleur?

Avez-vous des bonnes pratiques concernant l’utilisation de Royaume avec une analyse de recyclage?… Je sais que c’est une question générique, mais je n’ai rien trouvé à ce sujet sur Internet. Par exemple, je rencontre beaucoup de problèmes pour essayer de mettre en œuvre un simple changement de couleur sur une ligne. Par exemple, considérons cette utilisation typique:

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
   }

J'ai rencontré beaucoup de problèmes car je ne pouvais rien trouver sur Internet. Je sais que c'est parce que je ne sais pas comment utiliser correctement le royaume. Mais trouver le bon chemin est une lutte en soi. J'ai lu toute leur documentation mais en vain. 

EDIT: Depuis que j’ai été invité à -> Au lieu de dire «j’ai un tas de problèmes avec [ça]», décrivez votre (vos) problème (s) et nous essaierons de fournir des idées et des réponses à vos incompréhensions.

Donc mon problème est simple:

J'ai un utilisateur 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;
    }


}

Ce que j'ai mis dans un tableau RealmResults en utilisant:

RealmResults users = realm.where(RealmUser.class).findAll();

Je passe mon tableau d'utilisateurs à mon adaptateur d'utilisateur personnalisé:

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. 

}

Cela a un clic personnalisé écouteur: qui obtient l'élément recyclerview qui a été cliqué en utilisant:

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) {

    }
}

Que j'ajoute à mon recyclerView avec 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);
            }
    }));
26
Anghelut Florin

REPONSE POUR 0.89.0 ET PLUS

Pour les dernières versions, vous devez utiliser RealmRecyclerViewAdapter dans le référentiel realm-Android-adapters.

Versions:

  • Utilisez 1.5.0 à 2.X

  • Utilisez 2.1.1 jusqu'à 4.X

  • Utilisez 3.0.0 ci-dessus 5.X


ANCIENNE RÉPONSE POUR LES ANCIENNES VERSIONS:

J'ai créé cette RealmRecyclerViewAdapter en fonction de la mise en oeuvre de RealmBaseAdapter.

Ceci est pour v0.89.0 ET PLUS

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's 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();
    }
}

Ceci est pour v0.84.0 ET PLUS, MAIS SUPÉRIEUR À LA v0.89.0 (mis à jour pour la 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);
        }
    }
}

Ceci est pour PLUS DE 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();
    }
}
12
EpicPandaForce

Certaines des réponses ci-dessus incluent la réflexion, sans oublier qu'un RecyclerView sectionné causerait des complications. Ils ne prennent pas non plus en charge l’ajout et la suppression d’éléments. Voici ma version de l'adaptateur RecyclerView qui fonctionne avec Realm, prend en charge une section RecyclerView, ajoute et supprime également des éléments à des positions arbitraires si nécessaire.

Voici notre AbstractRealmAdapter qui prend en charge tous les éléments de bas niveau, affichant les en-têtes, les pieds de page, les éléments, chargeant les données dans RealmResults, gérant les types d'élément

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;
    }
}

Pour ajouter des éléments par une méthode ou supprimer des éléments par balayage, nous avons une extension sous la forme de AbstractMutableRealmAdapter qui ressemble à celle illustrée ci-dessous.

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);
        }
    }

}

Notez l'utilisation de l'interface OnSwipeListener qui ressemble à ceci

public interface OnSwipeListener {
    /**
     * @param position the position of the item that was swiped within the RecyclerView
     */
    void onSwipe(int position);
}

Ce SwipeListener est utilisé pour effectuer un balayage à supprimer dans notre TouchHelperCallback, qui à son tour est utilisé pour supprimer les objets du royaume directement et se présente comme suit

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());
    }
}

La démonstration complète de la mise en œuvre est disponible ici pour examen https://github.com/slidenerd/SpamWordList/tree/spamphraser_with_realmresults_base N'hésitez pas à suggérer des améliorations

J'ai remplacé les méthodes notifyXXX par notifyDataSetChanged. Les objets RealmResults sont des objets dynamiques, ce qui signifie qu'ils changent automatiquement lorsque les données sont mises à jour. J'ai essayé d'appeler les méthodes notifyXXX et ils ont provoqué une exception d'incohérence RecyclerView. avec des animations, vous tiendrons informés de la solution qui résout l'erreur d'incohérence tout en offrant une bonne expérience de l'adaptateur

9
PirateApp

Maintenant qu'avec Realm 0.88.2, nous pouvons créer un adaptateur RecyclerView qui le met à jour avec plus de précision que d'utiliser notifyDataSetChanged () à chaque fois. Cela peut être accompli en utilisant la nouvelle capacité, créez des méthodes personnalisées. 

Il suffit de remplacer la méthode equals dans l'objet royaume qui sera utilisé avec l'adaptateur Recycler. (Vous n'avez pas réellement besoin de remplacer égaux ... mais vous constaterez peut-être que les objets de domaine ne sont pas égaux lorsque vous vous en attendez. Cela entraînera des mises à jour inutiles de recyclerview après l'exécution de diff)

Ajoutez ensuite les (Java-diff-utils } _ de Google à vos dépendances Gradle. 

    compile 'com.googlecode.Java-diff-utils:diffutils:1.3.0'

À l'aide de cette implémentation RealmRecyclerViewAdapter, une copie de realmResults est créée au début et à chaque modification, pour être comparée aux modifications futures. Les modifications détectées sont utilisées pour mettre à jour RecyclerView selon les besoins

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's 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);
            }
        }
    };
}

}
3
luca992

L'implémentation de l'extension Realm à partir de Thorben Primke est une méthode très pratique Pour gérer les applications Recycler View avec des bases de données Realm. Son github a de bons exemples de la manière dont il peut être mis en œuvre. 

Je vais inclure le mien ici pour que vous ayez un exemple. Commencez par modifier votre génération de projet pour jitpack.io:

allprojects {
repositories {
    jcenter()
    maven { url "https://jitpack.io" }
}

Ensuite, votre module gradule pour pointer vers la bibliothèque: (note, vérifiez la dernière version)

dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.github.thorbenprimke:realm-recyclerview:0.9.20'

Créez la mise en page XML pour une vue de recycleur à l'aide de 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>

Maintenant, dans votre fragment RealmRecycler, obtenez un résultat de requête Realm de RealmObjects, gonflez et définissez un Primke RealmAdapter:

 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);

Enfin, configurez l’adaptateur de royaume pour tout ce que vous voulez pour des actions. J'ai un couple pour les clics et activé le balayage à supprimer pour supprimer des enregistrements de domaine.

      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;
                      }
                  }
          );
      }
  }
0
T_Dun

Votre message ne contient même pas une vraie question.

Avez-vous vérifié ce poste: http://gradlewhy.ghost.io/realm-results-with-recyclerview/ ?

Vous ne savez pas pourquoi vous n’utiliseriez pas simplement une ArrayList dans votre adaptateur et n’ajouteriez pas tous les éléments du RealmResult à cette liste. Quelqu'un pourrait-il expliquer pourquoi la solution proposée dans le blog serait meilleure?

0
lukasvo