【问题标题】:How to instantly update list item in ListView?如何立即更新 ListView 中的列表项?
【发布时间】:2016-08-28 20:58:29
【问题描述】:

我想要做的就是在我的提要中增加 Comment 对象的“like”值,并通知适配器该项目已更改。预期的行为应如下所示:1) 用户喜欢评论,2) ListView 更新为评论的新值。设置this.adapter.add(mComments.get(position - 1)); 会将其替换为之前的评论。使用 this.adapter.add(mComments.get(position) 会使应用程序崩溃。有没有办法做到这一点?我想既然它被删除了,你就不能真正把它加回来......除了升级到 RecyclerAdapter 并调用notifyItemChanged(int position),还有其他选择吗?

public class CommentAdapter extends ArrayAdapter<ParseObject> {

    protected Context mContext;
    protected List<ParseObject> mComments;
    private CommentAdapter adapter;

    ImageLoader profilePictureImageLoader;

    public CommentAdapter(Context context, List<ParseObject> comments) {
        super(context, R.layout.comment_listview_item, comments);
        mContext = context;
        mComments= comments;
        this.adapter = this;

        profilePictureImageLoader = new ImageLoader(new ProfilePictureFileCache(mContext));
    }

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    ViewHolder holder;

holder.likeImage.setOnClickListener(v -> {
    v.startAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.image_click));
    createLike(position);
});

    return convertView;
}

功能如下:

private void createLike(int position) {

        ParseQuery<ParseObject> query = new ParseQuery<>(ParseConstants.CLASS_COMMENT);
        query.whereEqualTo(ParseConstants.KEY_OBJECT_ID, getItem(position).getObjectId());
        query.findInBackground((comment, e) -> {
            // Find the single Comment object associated with the current ListAdapter position
            if (e == null) for (ParseObject commentObject : comment) {

                // Create a list to store the likers of this Comment
                List<String> likedBy = commentObject.getList("likedBy");
                System.out.println(likedBy);

                // If you are not on that list, then create a Like
                if (!(likedBy.contains(ParseUser.getCurrentUser().getObjectId()))) {

                    // Create new Like object
                    ParseObject newLike2 = new ParseObject(ParseConstants.CLASS_LIKE);
                    newLike2.put(ParseConstants.KEY_SENDER_ID, ParseUser.getCurrentUser());
                    newLike2.put(ParseConstants.KEY_COMMENT_OBJECT_ID, commentObject);
                    Toast.makeText(getContext(), "Comment liked", Toast.LENGTH_SHORT).show();
                    newLike2.saveInBackground();

                    // Add unique User objectId to likedBy array in Parse
                    commentObject.addAllUnique("likedBy", Collections.singletonList(ParseUser.getCurrentUser().getObjectId()));
                    commentObject.saveInBackground();

                    // Increment the likeCount in the Comment feed
                    incrementLikeCount(commentObject, position);

                    // Initiate Like notification
                    handleLikeNotification(query, commentObject);

                } else {
                    Toast.makeText(getContext(), "You already liked this Comment", Toast.LENGTH_SHORT).show();
                }

            }
            else {
                Log.e("Error", e.getMessage());
            }
        });

    }

private void incrementLikeCount(ParseObject commentObject, int position); 

    // Increment likeCount on related Comment object
    commentObject.increment("likeCount");
    commentObject.saveInBackground();

    this.adapter.remove(mComments.get(position));
    this.adapter.add(mComments.get(position));
    this.adapter.notifyDataSetChanged();

    }

我得到以下异常:

08-28 22:46:04.359 28894-28894/com.yitter.android E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.yitter.android, PID: 28894
    java.lang.IndexOutOfBoundsException: Invalid index 3, size is 2
        at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
        at java.util.ArrayList.get(ArrayList.java:308)
        at com.yitter.comment.CommentAdapter.lambda$incrementLikeCount$33(CommentAdapter.java:260)
        at com.yitter.comment.CommentAdapter.access$lambda$6(CommentAdapter.java:0)
        at com.yitter.comment.CommentAdapter$$Lambda$9.done(Unknown Source)
        at com.parse.ParseTaskUtils$2$1.run(ParseTaskUtils.java:116)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:148)
        at android.app.ActivityThread.main(ActivityThread.java:5417)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

【问题讨论】:

  • 这只是一个猜测。我认为mComments 是对适配器使用的同一个列表的引用。如果是这种情况,this.adapter.remove(mComments.get(position)) 将从mComments 中删除元素并减小其大小,因此出现异常。
  • 这个假设可能是正确的。该项目不再存在,因此无法重新添加。有没有办法在 ListView 中避免这种情况,以便可以立即更改项目?
  • 如果是这种情况,您不需要添加和删除项目,只需更新适配器即可显示更改。
  • 那么,您想更新列表视图中的一行,对吧? (更新特定行的点赞数)如果是这样,你试过这个stackoverflow.com/a/3727813/1920068 吗?它对我有用

标签: java android listview parse-platform listadapter


【解决方案1】:

您根本不需要添加/删除视图。

您应该更新您的模型(如果您对我假设的每一行都有一个评论对象,并且使用“喜欢”计数)然后调用 notifydatasetchanged()。

另外,您可能应该更新为使用 RecycleView,这是他们创建它的原因之一,因此您可以只对一项而不是全部调用 notifyitemchanged()。

【讨论】:

  • notifydatasetchanged() 单独似乎不会更新项目。
【解决方案2】:

好的,我知道如何解决您的问题。

这是你的一段代码:

private void incrementLikeCount(ParseObject commentObject, int position); 

    // Increment likeCount on related Comment object
    commentObject.increment("likeCount");
    commentObject.saveInBackground();

    this.adapter.remove(mComments.get(position));
    this.adapter.add(mComments.get(position));
    this.adapter.notifyDataSetChanged();

}

看,如果列表大小等于 4,并且您调用 incrementLikeCountposition 的值等于 3(列表的最后一个元素),应用程序将崩溃。您首先删除列表的一个对象(因此它的大小现在将是 3(并且它的最后一个索引位置等于 2),并且在您尝试从列表中检索相同的元素并传递相同的 position 值(@ 987654325@)。只要最后一个索引现在等于2,并且您尝试获取索引中的元素3,应用程序就会崩溃。

考虑把代码改成这样:

private void incrementLikeCount(ParseObject commentObject, int position); 

    // Increment likeCount on related Comment object
    commentObject.increment("likeCount");
    commentObject.saveInBackground();

    this.adapter.remove(commentObject);
    this.adapter.add(commentObject);
    this.adapter.notifyDataSetChanged();

}

但是看,您正在将同一个对象删除并添加到列表中!!!你能做的只是更新对象并调用this.adapter.notifyDataSetChanged();

private void incrementLikeCount(ParseObject commentObject, int position); 

    // Increment likeCount on related Comment object
    commentObject.increment("likeCount");
    commentObject.saveInBackground();

    this.adapter.notifyDataSetChanged();

}

【讨论】:

  • 我从原来的 mComments 列表中得到了这个职位。
  • 您介意发布与您遇到的问题相关的全部代码,以便我们更好地为您提供帮助吗?干杯:)
  • 嗨,我认为如果你更新你的评论对象然后执行 YOURLISTVIEW.refresh() 你的问题就会解决
  • 酷。是的,我希望 this.adapter.notifyDataSetChanged(); 这能正常工作,但它根本不会更新列表项......
  • mComments 列表是否与适配器中的列表相同?它们在内存中有相同的引用吗?如果没有,这就是它不起作用的原因。
【解决方案3】:

试试这个:

private void incrementLikeCount(ParseObject commentObject, int position); 
    commentObject.increment("likeCount");
    mComments.get(position).increment("likeCount");
    this.adapter.notifyDataSetChanged();      
    commentObject.saveInBackground();
}

或者,如果commentObject 的更改比增加的likeCount 更多,您可以这样做:

private void incrementLikeCount(ParseObject commentObject, int position); 
    commentObject.increment("likeCount");
    this.adapter.remove(position);
    this.adapter.add(commentObject);
    this.adapter.notifyDataSetChanged();      
    commentObject.saveInBackground();
}

【讨论】:

  • 这成功了!为什么在保存对象之前notifyDataSetChanged
  • @bluemunch 本地对象mComments.get(position)已经被修改,保存它只会更新云对象,你不需要等待刷新GUI。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-30
  • 2020-03-23
  • 1970-01-01
  • 1970-01-01
  • 2021-08-18
  • 2020-10-16
  • 1970-01-01
相关资源
最近更新 更多