领域升级到0.89.0打破了RecyclerView

时间:2016-05-24 21:31:34

标签: android realm

我刚刚开始在我的某个项目中使用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;
    }
}

其他文件(类,接口,布局等)非常简单,因此我不会将它们粘贴到此处以保持问题的可读性,但它们可以在存储库中使用。

现在症状:

  • 领域版本0.88.2(分支大师):
    • 点击&#39;添加项目&#39;按钮使用平滑动画在列表顶部添加项目
    • 触摸项目允许拖动它以重新排序列表
    • 所以它按预期工作
  • 领域版本0.89.0(分支领域-0.89.0):
    • 点击&#39;添加项目&#39;按钮:
      • 第一次点击:将项目添加到领域但不更新视图
      • 进一步点击:崩溃应用程序(&#34; java.lang.IndexOutOfBoundsException:检测到不一致。无效的视图持有者适配器positionViewHolder {349439e7 position = 2 id = 0,oldPos = 1,pLpos:1 scrap [attachedScrap] tmpDetached no父}&#34)
    • 触摸项目:
      • 在第一次交换时停止拖动
      • 交换领域中的项目(可以通过强制重新创建活动来查看,从而根据新数据构建RecyclerView)
      • 将视图恢复为原始状态或交换其他元素??

两个分支之间唯一发生变化的是Realm版本。 我四处寻找类似的问题而没有运气。在这一点上,我不确定这是否是破坏RecyclerView行为的0.89.0+,或者如果这是不应该以这种方式工作的0.88.2。

非常感谢任何帮助。

1 个答案:

答案 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 可以达到相同的效果。