我刚刚开始在我的某个项目中使用Realm,当尝试将领域升级到0.89.0或更高版本时,我的RecyclerView行为完全崩溃了。我试图找出问题所在并归结为此示例:https://bitbucket.org/pr-shadoko/realmrecyclerviewtest 以下是主要课程: 活动:
public class MainActivity extends AppCompatActivity {
ItemTouchHelper itemTouchHelper;
RecyclerView recyclerView;
TagsAdapter adapter;
Realm realm;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RealmConfiguration config = new RealmConfiguration.Builder(this).build();
Realm.setDefaultConfiguration(config);
realm = Realm.getDefaultInstance();
adapter = new TagsAdapter(realm, new OnDragStartListener() {
@Override
public void onDragStart(RecyclerView.ViewHolder viewHolder) {
itemTouchHelper.startDrag(viewHolder);
}
});
itemTouchHelper = new ItemTouchHelper(new TagTouchHelperCallback(adapter));
recyclerView = (RecyclerView) findViewById(R.id.rv);
recyclerView.setAdapter(adapter);
itemTouchHelper.attachToRecyclerView(recyclerView);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case R.id.action_add:
Tag tag = new Tag();
tag.setTag("#tag" + tag.getTagId());
realm.beginTransaction();
realm.copyToRealmOrUpdate(tag);
realm.commitTransaction();
adapter.notifyItemInserted(1);
default:
return super.onOptionsItemSelected(item);
}
}
}
RecyclerView适配器:
public class TagsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements ItemTouchHelperAdapter {
private static final int TYPE_TAG = 0;
private static final int TYPE_HEADER = 1;
private Realm realm;
private RealmResults<Tag> tags;
private OnDragStartListener dragStartListener;
public TagsAdapter(Realm realm, OnDragStartListener dragStartListener) {
this.realm = realm;
this.tags = realm.where(Tag.class).findAllSorted("order", Sort.DESCENDING);
this.dragStartListener = dragStartListener;
setHasStableIds(true);
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch(viewType) {
case TYPE_TAG:
View taskView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
return new TagViewHolder(taskView);
case TYPE_HEADER:
View headerView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
return new HeaderViewHolder(headerView);
default:
return null;
}
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int adapterPosition) {
switch(holder.getItemViewType()) {
case TYPE_TAG:
onBindViewHolderTag((TagViewHolder) holder, adapterPosition);
break;
case TYPE_HEADER:
onBindViewHolderHeader((HeaderViewHolder) holder, adapterPosition);
break;
default:
}
}
private void onBindViewHolderTag(final TagViewHolder holder, final int adapterPosition) {
final Tag tag = tags.get(getDataSetPosition(adapterPosition));
holder.title.setText(tag.getTag());
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("TAGS", "item clicked: id=" + tag.getTagId() + " ; adapterPosition=" + adapterPosition + " ; datasetPosition=" + getDataSetPosition(adapterPosition));
}
});
holder.itemView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if(MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
dragStartListener.onDragStart(holder);
}
return false;
}
});
}
private void onBindViewHolderHeader(HeaderViewHolder holder, int adapterPosition) {
holder.header.setText("TITLE");
}
private int getDataSetPosition(int adapterPosition) {
switch(getItemViewType(adapterPosition)) {
case TYPE_TAG:
return adapterPosition - 1;
case TYPE_HEADER:
default:
return RecyclerView.NO_POSITION;
}
}
@Override
public int getItemCount() {
return tags.size() + 1;
}
@Override
public long getItemId(int adapterPosition) {
switch(getItemViewType(adapterPosition)) {
case TYPE_TAG:
return tags.get(getDataSetPosition(adapterPosition)).getTagId();
case TYPE_HEADER:
default:
return RecyclerView.NO_ID;
}
}
@Override
public int getItemViewType(int adapterPosition) {
if(adapterPosition == 0) {
return TYPE_HEADER;
}
return TYPE_TAG;
}
@Override
public boolean onItemMoved(final int fromAdapterPosition, final int toAdapterPosition) {
Log.i("TAGS", "move from " + fromAdapterPosition + " to " + toAdapterPosition);
if(getItemViewType(toAdapterPosition) != TYPE_TAG) {
return false;
}
Tag task1 = tags.get(getDataSetPosition(fromAdapterPosition));
Tag task2 = tags.get(getDataSetPosition(toAdapterPosition));
Log.i("TAGS", "realm pos from=" + getDataSetPosition(fromAdapterPosition) + " ; to=" + getDataSetPosition(toAdapterPosition));
int order1 = task1.getOrder();
realm.beginTransaction();
task1.setOrder(task2.getOrder());
task2.setOrder(order1);
realm.copyToRealmOrUpdate(task1);
realm.copyToRealmOrUpdate(task2);
realm.commitTransaction();
notifyItemMoved(fromAdapterPosition, toAdapterPosition);
return true;
}
@Override
public void onItemSwiped(RecyclerView.ViewHolder holder, int direction) {}
public class TagViewHolder extends RecyclerView.ViewHolder {
public final TextView title;
public TagViewHolder(View itemView) {
super(itemView);
this.title = (TextView) itemView.findViewById(R.id.label);
}
}
public class HeaderViewHolder extends RecyclerView.ViewHolder {
public final TextView header;
public HeaderViewHolder(View itemView) {
super(itemView);
this.header = (TextView) itemView.findViewById(R.id.label);
}
}
}
Tag表定义:
public class Tag extends RealmObject {
@Ignore
private final static Object nextIdLock = new Object();
@Ignore
private static Integer nextId;
@PrimaryKey
@Required
private Integer tagId;
@Required
private Integer order;
@Required
private String tag;
public Tag() {
synchronized(nextIdLock) {
if(nextId == null) {
Realm realm = Realm.getDefaultInstance();
RealmResults<Tag> tags = realm.where(Tag.class).findAll();
if(tags.size() != 0) {
nextId = tags.max("tagId").intValue() + 1;
} else {
nextId = 0;
}
realm.close();
}
order = tagId = nextId++;
}
}
public Integer getTagId() {
return tagId;
}
public Tag setTagId(Integer tagId) {
this.tagId = tagId;
return this;
}
public Integer getOrder() {
return order;
}
public Tag setOrder(Integer order) {
this.order = order;
return this;
}
public String getTag() {
return tag;
}
public Tag setTag(String tag) {
this.tag = tag;
return this;
}
}
其他文件(类,接口,布局等)非常简单,因此我不会将它们粘贴到此处以保持问题的可读性,但它们可以在存储库中使用。
现在症状:
两个分支之间唯一发生变化的是Realm版本。 我四处寻找类似的问题而没有运气。在这一点上,我不确定这是否是破坏RecyclerView行为的0.89.0+,或者如果这是不应该以这种方式工作的0.88.2。
非常感谢任何帮助。
答案 0 :(得分:1)
那是因为在0.89.0中,要在RealmResults
上创建正确的迭代行为,本地提交仅在下一个looper事件上更新RealmResults,而不是立即更新。
所以这里的代码
realm.beginTransaction();
task1.setOrder(task2.getOrder());
task2.setOrder(order1);
realm.copyToRealmOrUpdate(task1);
realm.copyToRealmOrUpdate(task2);
realm.commitTransaction();
notifyItemMoved(fromAdapterPosition, toAdapterPosition);
将失败,因为该列表尚未在commitTransaction()
之后更新。
我一直想找出一种解决此问题的智能方法,但无济于事,尽管强制an immediate refresh via the HandlerController 可以达到相同的效果。