Java – RecyclerView automatically scrolls up and flashes

RecyclerView automatically scrolls up and flashes… here is a solution to the problem.

RecyclerView automatically scrolls up and flashes

Basically, I use RecyclerView and gridAdapter to load images from the server. But the problem is that RecyclerView's projects flicker in weird ways. I’ve tried all possible solutions but none have worked so far.

I tried to update the glide version from 4.4.0 to 4.8.0 but it was in vain. I also tried disabling RecyclerView's animation, but that didn’t help. Can anyone help me with this?

See how Images are blinking

Code:

GridLayoutManager gridLayoutManager = new GridLayoutManager(v.getContext(),3);
gridLayoutManager.setSmoothScrollbarEnabled(true);
gridLayoutManager.setItemPrefetchEnabled(true);
gridLayoutManager.setInitialPrefetchItemCount(20);

posts_rView.setLayoutManager(gridLayoutManager);
posts_rView.setItemAnimator(null);
posts_rView.setHasFixedSize(true);

gridPostAdapter=new StarredAdapter(timelineDataList);
posts_rView.setAdapter(gridPostAdapter);

Data update code:

private  Emitter.Listener handlePosts = new Emitter.Listener(){

@Override
    public void call(final Object... args){
        try {
            JSONArray jsonArray=(JSONArray)args[0];
            Needle.onMainThread().execute(() -> {
                timelineDataList.clear();
                swipeRefreshLayout.setRefreshing(false);

for(int i=0; i<jsonArray.length(); i++){
                    try {
                        JSONArray arr=jsonArray.getJSONArray(i);
                        JSONObject ob=jsonArray.getJSONObject(i);

post_username=ob.getString("_pid");
                        post_fullname=ob.getString("owner_fullname");

if(ob.has("owner_profPic"))post_profPic=ob.getString("owner_profPic");
                        else post_profPic="";

post_time=ob.getString("time");

post_link=ob.getString("img_link");
                        likes_counter=ob.getString("likes_counter");
                        comments_counter=ob.getString("comments_counter");
                        if(ob.has("caption")) post_caption=ob.getString("caption");
                        else post_caption=null;

Skipping Private Posts
                        if(ob.getString("private_post_stat").equals("yes")&&!post_username.equals(my_username)) {
                            continue;
                        }
                        else
                            private_post_stat = ob.getString("private_post_stat");

comment_disabled=ob.getString("comment_disabled");

share_disabled=ob.getString("share_disabled");

download_disabled=ob.getString("download_disabled");

if(ob.has("short_book_content")) short_book_content=ob.getString("short_book_content");
                        else short_book_content=null;
                        society_name_adp=ob.getString("society");

addTimelineData(post_username,post_fullname,post_profPic,post_time,post_link,post_caption,
                                private_post_stat,comment_disabled,share_disabled,download_disabled,likes_counter,comments_counter,short_book_content,society_name_adp);

} catch (JSONException e) {
                        e.printStackTrace();
                    }
                }

RecyclerView.Adapter adapter=posts_rView.getAdapter();
                posts_rView.setAdapter(null);
                posts_rView.setAdapter(adapter);
            });
        } catch (Exception e) {
            Log.e("error",e.toString());
        }
    }
};

private void addTimelineData(String username,String fullname,String post_profPic,String time,String img_link,String caption,
                             String private_post_stat,String comment_disabled,String share_disabled,String download_disabled,String likes_counter,
                             String comments_counter,String short_book_content,String society_name_adp){
    boolean isRepeated = false;
    for(TimelineData data:timelineDataList){
        if (data.getTime().equals(time)) {
            isRepeated = true;
        }
    }

if(!isRepeated){
        timelineDataList.add(new TimelineData(username,fullname,post_profPic,time,img_link,caption,private_post_stat,comment_disabled,share_disabled,download_disabled,likes_ counter,comments_counter,short_book_content,society_name_adp));
        gridPostAdapter.notifyDataSetChanged();
         posts_rView.scrollToPosition(gridPostAdapter.getItemCount()-1);
        posts_rView.scrollToPosition(0);
    }

gridPostAdapter.notifyItemInserted(timelineDataList.size()-1);
}

Adapter class:

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

loading img
    Glide.with( parent.getContext()).asBitmap().load(arrayList.get(position)).apply(new RequestOptions()
        .override(200, 200)
        .dontAnimate()
        .placeholder(new ColorDrawable(Color.parseColor("#20001919"))))
        .thumbnail(0.1f)
        .into(holder.img);
}

@Override
public int getItemCount() {
    return arrayList.size();
}

@Override
public long getItemId(int position) {
    return position;
}

@Override
public int getItemViewType(int position) {
    return position;
}

Solution

I

don’t quite understand why there is flickering and repositioning to the first element in your case, as I don’t see the update policy for your RecyclerView. However, I would like to make some suggestions that may solve the problem.

  1. I recommend that you remove the setInitialPrefetchItemCount and setItemPrefetchEnabled configurations when setting up GridLayoutManager. If you have a nested RecyclerView, this will help your situation.
  2. Each time you update data from the server, you are setting up the adapter. I’m guessing you’re calling the update action code while scrolling through the project. You shouldn’t do that. Also, remove the adapter that sets RecyclerView each time the dataset is updated. Just use notifyDataSetChanged after each update. Instead of clearing the timelineDataList, attach the new item, and then call notifyDataSetChanged on your adapter.
  3. Each time you insert a list, you call notifyDataSetChanged in addTimelineData. This should only be done after all elements have been added to the list.

So I’d like to recommend the following code to set up your adapter and update your RecyclerView. Note that I didn’t test the code and you may need to modify some errors that may occur.

Set up the code for the layout manager and adapter.

GridLayoutManager gridLayoutManager = new GridLayoutManager(v.getContext(),3);
posts_rView.setLayoutManager(gridLayoutManager);
posts_rView.setHasFixedSize(true);

gridPostAdapter = new StarredAdapter(timelineDataList);
posts_rView.setAdapter(gridPostAdapter);

Update the code for the list.

private  Emitter.Listener handlePosts = new Emitter.Listener(){

@Override
    public void call(final Object... args){
        try {
            JSONArray jsonArray = (JSONArray)args[0];
            Needle.onMainThread().execute(() -> {

 Do not clear the list. Just append the new data in the list instead
                 timelineDataList.clear();

swipeRefreshLayout.setRefreshing(false);

for(int i = 0; i < jsonArray.length(); i++){
                    try {
                        JSONObject ob = jsonArray.getJSONObject(i);

post_username = ob.getString("_pid");
                        post_fullname = ob.getString("owner_fullname");
                        if(ob.has("owner_profPic")) post_profPic = ob.getString("owner_profPic");
                        else post_profPic = "";

post_time = ob.getString("time");

post_link = ob.getString("img_link");
                        likes_counter = ob.getString("likes_counter");
                        comments_counter = ob.getString("comments_counter");
                        if(ob.has("caption")) post_caption = ob.getString("caption");
                        else post_caption = null;

Skipping Private Posts
                        if(ob.getString("private_post_stat").equals("yes")&&!post_username.equals(my_username)) {
                            continue;
                        }
                        else
                            private_post_stat = ob.getString("private_post_stat");

comment_disabled = ob.getString("comment_disabled");
                        share_disabled = ob.getString("share_disabled");
                        download_disabled = ob.getString("download_disabled");

if (ob.has("short_book_content")) short_book_content = ob.getString("short_book_content");
                        else short_book_content = null;

society_name_adp = ob.getString("society");
                        addTimelineData(post_username, post_fullname, post_profPic, post_time, post_link,post_caption, private_post_stat, comment_disabled, share_disabled, download_disabled, likes_ counter, comments_counter, short_book_content, society_name_adp);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }

gridPostAdapter.notifyDataSetChanged();
            });

} catch (Exception e) {
            Log.e("error",e.toString());
        }
    }
};

private void addTimelineData(String username, String fullname, String post_profPic, String time, String img_link, String caption, String private_post_stat, String comment_disabled, String share_disabled, String download_disabled, String likes_counter, String comments_counter, String short_book_content, String society_name_adp) {

boolean isRepeated = false;
    for(TimelineData data:timelineDataList){
        if (data.getTime().equals(time)) {
            isRepeated = true;
        }
    }

if(!isRepeated){
        timelineDataList.add(new TimelineData(username,fullname,post_profPic,time,img_link,caption,private_post_stat,comment_disabled,share_disabled,download_disabled,likes_ counter,comments_counter,short_book_content,society_name_adp));

 Do not call notifyDataSetChanged each time you are adding an item. This will be called in the call function above. So remove this line.
         gridPostAdapter.notifyDataSetChanged();
    }
}

Try adding some pagination in the server-side API if it doesn’t already exist, so you can get the next 20 datasets instead of getting the whole data again as you scroll down.

Hope this helps.

Related Problems and Solutions