问题描述
你们有关于使用 Realm 和 recyclerview 的最佳实践吗?我知道这是一个通用问题,但我在互联网上没有找到任何相关信息.例如,我在尝试对一行进行简单的颜色更改时遇到了很多麻烦.例如考虑这个典型的用法:
Do you guys have any best practices regarding using realm with a recyclerview ?I know it's generic question but I found nothing on it on the internet. For example I run into a lot of troubles trying to implement a simple color change on a row . For example consider this typical usage:
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
}
我遇到了很多问题,因为我在互联网上找不到任何东西.我知道这是因为我不知道如何正确使用领域.但找到正确的道路本身就是一场斗争.我阅读了他们所有的文档,但无济于事.
I ran into a lot of issues since I couldn't find anything on the internet. I know this is because I don't know how to properly use realm. But finding the right way is a struggle in itself . I read all their documentation but to no avail.
由于我被要求 --> 与其说我有一堆问题 [that]",请描述您的问题,我们将尝试为您的不理解提供见解和答案.
EDIT : Since I was asked to --> Instead of saying "I have a bunch of issues with [that]", describe your issue(s) and we'll try to provide insights and answers to your incomprehensions.
所以我的问题很简单:
我有一个 RealmUser :
I have a 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 数组中:
Which I put in a RealmResults array using :
RealmResults users = realm.where(RealmUser.class).findAll();
我将我的用户数组传递给我的自定义用户适配器:
I pass my user array to my custom user adapter :
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.
}
具有自定义单击侦听器:获取使用以下方法单击的 recyclerview 项:
That has a custom click Listener : that gets recyclerview item that was clicked using :
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) {
}
}
我使用 addOnItemTouchListener 添加到我的 recyclerView 中:
Which I add to my recyclerView with 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);
}
}));
推荐答案
ANSWER FOR 0.89.0 及以上
对于最新版本,您应该使用realm-android-adapters存储库中的RealmRecyclerViewAdapter.
For the latest versions, you should use RealmRecyclerViewAdapter in the realm-android-adapters repository.
版本:
使用 1.5.0 到 2.X
Use 1.5.0 up to 2.X
使用 2.1.1 到 4.X
Use 2.1.1 up to 4.X
在 5.X 以上使用 3.0.0
Use 3.0.0 above 5.X
旧版本的旧答案:
我根据RealmBaseAdapter
的实现制作了这个RealmRecyclerViewAdapter
.
I made this RealmRecyclerViewAdapter
based on the implementation of 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'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();
}
}
这适用于 v0.84.0 及更高版本,但比 v0.89.0 旧(针对 v0.87.5 更新):
This is for v0.84.0 AND ABOVE, BUT OLDER THAN v0.89.0 (updated for 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();
}
}
这篇关于在回收站视图中使用领域的最佳实践?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!