Search code examples
javaandroidlistviewparse-platformlistadapter

How to instantly update list item in ListView?


All I want to do is increment the "like" value of the Comment object in my feed and notify the adapter that the item has changed. The expected behavior should be as follows: 1) User likes the Comment, 2) ListView updates with the new value for the Comment. Setting this.adapter.add(mComments.get(position - 1)); will replace it with the Comment before. Using this.adapter.add(mComments.get(position) crashes the app. Is there any way to do this? I guess since it's removed you can't really add it back... Besides upgrading to RecyclerAdapter and calling notifyItemChanged(int position), is there an alternative?

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;
}

Functions follow:

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

    }

I get the following exception:

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)

Solution

  • Try this:

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

    Or, if the commentObject has more changes then the incremented likeCount, you can do this:

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