android - RecyclerView 元素更新 + 异步网络调用

标签 android android-recyclerview

我有一个按预期工作的 recyclerview。我在布局中有一个填充列表的按钮。该按钮应该进行异步调用,结果,我更改了按钮的外观。这一切都很好。

但是当我单击按钮并快速向下滚动列表时,异步调用的结果会更新新 View 的按钮(代替旧 View 的 View )。我该如何处理?我可以处理特定 View 何时被重用吗?

更新:

执行异步调用和更新 ui 的适配器类的代码 fragment 。

@Override
public void onBindViewHolder(CommentsViewHolder holder, int position) {
    try {

        Comments comment = comments.get(position);
        holder.bindView(comment,position);

    }
    catch(Exception ex){ex.printStackTrace();}

}

@Override
public int getItemCount() {
    if(comments==null)
    {return 0;}
    return comments.size();
    //return comments.length();
}



public class CommentsViewHolder extends RecyclerView.ViewHolder {
    TextView score ;

    TextView commentText;
    TextView commentTime;
    TextView avatarId;
    ImageButton minusOne;
    ImageButton plusOne;
    ParseObject model;

    public CommentsViewHolder(View itemView) {
        super(itemView);
        //itemView.setBackgroundColor(Color.DKGRAY);
        minusOne =(ImageButton)itemView.findViewById(R.id.decScore);
        plusOne =(ImageButton)itemView.findViewById(R.id.incScore);
        commentText = (TextView)itemView.findViewById(R.id.comment);
        score = (TextView)itemView.findViewById(R.id.commentScore);
        commentTime =(TextView)itemView.findViewById(R.id.commentTime);
        avatarId = (TextView)itemView.findViewById(R.id.ivUserAvatar);
    }
    public void bindView(Comments comment, int position) {


        commentText.setText(comment.getCommentText());

        score.setText(Integer.toString(comment.getScore()));
        String timeText = DateUtils.getRelativeTimeSpanString(  comment.getCreatedAt().getTime(), System.currentTimeMillis(), DateUtils.SECOND_IN_MILLIS).toString();
        timeText = timeText.replace("hours","hrs");
        timeText = timeText.replace("seconds","secs");
        timeText = timeText.replace("minutes","mins");
        commentTime.setText(timeText);
        int commentHandler = comment.getCommenterHandle();
        String commenterNumber = "";
        if(commentHandler==0)
        {
            commenterNumber = "OP";
        }
        else{
            commenterNumber = "#"+commentHandler;
        }
        avatarId.setText( commenterNumber);
        model = comment;

        String choice = "none";
        minusOne.setEnabled(true);
        plusOne.setEnabled(true);
        minusOne.setVisibility(View.VISIBLE);
        plusOne.setVisibility(View.VISIBLE);
        for (ParseObject choiceIter : choices) {


            if ((choiceIter.getParseObject("comment").getObjectId()).equals(comment.getObjectId())) {
                choice = choiceIter.getString("userChoice");

                break;
            }
        }


        Log.i("debug",comment.getCommentText()+" "+comment.getScore()+" "+choice);

        switch (choice) {

            case "plusOne":
                Log.i("darkplus","setting darkplus");
                plusOne.setImageResource(R.drawable.ic_add_circle_black_18dp);
                plusOne.setOnClickListener(reversePlusOneOnClickListener);
                //minusOne.setOnClickListener(minusOneOnClickListener);
                minusOne.setVisibility(View.GONE);
                break;

            case "minusOne":
                Log.i("darkminus","setting darkminus");
                minusOne.setImageResource(R.drawable.ic_remove_circle_black_18dp);
                minusOne.setOnClickListener(reverseMinusOneOnClickListener);
                //plusOne.setOnClickListener(plusOneOnClickListener);
                plusOne.setVisibility(View.GONE);
                break;

            case "none":
                Log.i("darkregular","setting regular");
                minusOne.setImageResource(R.drawable.ic_remove_black_18dp);
                plusOne.setImageResource(R.drawable.ic_add_black_18dp);

                plusOne.setOnClickListener(plusOneOnClickListener);
                minusOne.setOnClickListener(minusOneOnClickListener);
                break;
        }

    }


    View.OnClickListener reversePlusOneOnClickListener = new View.OnClickListener() {

        @Override
        public void onClick(View v) {

            if (!FourUtils.isConnected(v.getContext())) {
                return;
            }

            minusOne.setEnabled(false);
            plusOne.setEnabled(false);
            model.increment("plusOne", -1);
            model.increment("score", -1);

            model.saveEventually(new SaveCallback() {
                @Override
                public void done(ParseException e) {

                    if (e == null) {
                        ParseQuery<ParseObject> query = ParseQuery.getQuery("CommentChoice");
                        query.whereEqualTo("user", ParseUser.getCurrentUser());
                        query.whereEqualTo("comment", model);
                        query.fromPin(Four.COMMENT_CHOICE);
                        query.getFirstInBackground(new GetCallback<ParseObject>() {
                            @Override
                            public void done(ParseObject parseObject, ParseException e) {
                                if (e == null) {
                                    if (parseObject == null) {
                                        parseObject = ParseObject.create("CommentChoice");
                                        parseObject.put("comment", model);
                                        parseObject.put("user", ParseUser.getCurrentUser());

                                    }
                                    parseObject.put("userChoice", "none");
                                    parseObject.pinInBackground(Four.COMMENT_CHOICE, new SaveCallback() {
                                        @Override
                                        public void done(ParseException e) {
                                            if (e == null) {
                                                score.setText(Integer.toString(model.getInt("score")));
                                                //votes.setText((model.getInt("minusOne") + model.getInt("plusOne")) + " votes");

                                                minusOne.setVisibility(View.VISIBLE);
                                                plusOne.setImageResource(R.drawable.ic_add_black_18dp);
                                                plusOne.setOnClickListener(plusOneOnClickListener);
                                                minusOne.setEnabled(true);
                                                plusOne.setEnabled(true);
                                               // minusOne.setOnClickListener(minusOneOnClickListener);
                                                BusProvider.getInstance().post(new NewCommentChoicesAdded());
                                            } else {
                                                e.printStackTrace();
                                            }
                                        }
                                    });
                                }
                                else{e.printStackTrace();}
                            }
                        });
                    } else {
                        e.printStackTrace();
                        Log.i("plus1 error", e.getMessage());
                    }

                }
            });
        }
    };

最佳答案

异步代码完成后,您应该更新数据,而不是 View 。更新数据后,告诉适配器数据发生了变化。 RecyclerView 会注意到这一点并重新呈现您的 View 。
使用回收 View (ListView 或 RecyclerView)时,您无法知道 View 代表什么项目。在您的情况下,该 View 在异步工作完成之前被回收,并被分配给您的不同数据项。
所以永远不要修改 View 。始终修改数据并通知适配器。 bindView 应该是你处理这些情况的地方。

关于android - RecyclerView 元素更新 + 异步网络调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31748756/

相关文章:

android - Retrofit 2、GSON 和自定义解串器

Android 自定义适配器不显示所有项目

android - Android 广播接收器内的线程

android - 房间数据库中的空数组列表

android - 从 Play 服务中删除了帐户选择器?

java - androidx.appcompat.widget.SearchView setSearchableInfo() 在某些设备上抛出 Resources$NotFoundException

Android 波纹效果被选定状态覆盖

android - 如何在切换到另一个选项卡之前更新选项卡布局

android - 使用 SpanSizeLookup 为 GridLayoutManager 中的项目设置跨度

java - 回收站 View - 滚动时调整项目 View 的大小(用于类似轮播的效果)