RecyclerView元素更新+异步网络调用 [英] RecyclerView element update + async network call

查看:60
本文介绍了RecyclerView元素更新+异步网络调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a recyclerview which works as expected. I have a button in the layout that fills the list. The button is supposed to make a async call, and on result, I change the button's look. All this happens fine.

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

But when I click on the button and scroll down the list fast, the async call's result updates the new view's button(the view that is in place of the old one). How do I handle this? Can I have a handle on when a particular view gets reused?

更新:

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

Code piece of the adapter class that does the async call and the updation of ui.

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

                }
            });
        }
    };

推荐答案

异步代码完成后,您应该更新数据,而不是视图.更新数据后,告诉适配器数据已更改. RecyclerView会注意到这一点并重新呈现您的视图.
使用回收视图(ListView或RecyclerView)时,您不知道视图代表的项目.对于您而言,该视图会在异步工作完成之前回收,并分配给您的另一项数据.
因此,切勿修改视图.始终修改数据并通知适配器. bindView应该是您处理这些情况的地方.

When the async code is done, you should update the data, not the views. After updating the data, tell the adapter that the data changed. The RecyclerView gets note of this and re-renders your view.
When working with recycling views (ListView or RecyclerView), you cannot know what item a view is representing. In your case, that view gets recycled before the async work is done and is assigned to a different item of your data.
So never modify the view. Always modify the data and notify the adapter. bindView should be the place where you treat these cases.

这篇关于RecyclerView元素更新+异步网络调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆