bluemunch bluemunch - 3 months ago 11
Android Question

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)

Answer

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