RecyclerView Scroll Slow - setHasStableIds not working, possible to preload more than one offscreen views?

Viewed 531

I have been trying to fix my slow scrolling in a Twitter like app using RecyclerView by using the suggestions from this [link][1] and have had trouble with #7 "setHasStableIds(true)". When I don't override getItemId(), I only get about 6 items in my RecyclerView out of 30ish. When I override it and return position or the tweetStatusID for the function, it still lags like when I wasn't using setHasStableIds(true) for my adapter.

UPDATED: I have added some AsyncTasks which has improved my speed but it's still slow, I was curious if any more improvements can be made or if it's possible to preload more views so more are ready when scrolling fast.

MyFeed onCreate():

super.onCreate(savedInstanceState);
setContentView(R.layout.activity_feed);
final RecyclerView recyclerView = findViewById(R.id.rv_feed);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());

DatabaseReference databaseReference;

// Create new Twitter configuration
ConfigurationBuilder cb = new ConfigurationBuilder();

// Create Twitter instance for retweeting
TwitterFactory tf = new TwitterFactory(cb.build());
twitter = tf.getInstance();

authTokenToken = getIntent().getStringExtra("AUTH_TOKEN_TOKEN");
authTokenSecret = getIntent().getStringExtra("AUTH_TOKEN_SECRET");

// Firebase Auth
mAuth = FirebaseAuth.getInstance();
dbFeedPath = getResources().getString(R.string.isu_feed);
databaseReference = FirebaseDatabase.getInstance().getReference(dbFeedPath);

databaseReference.addValueEventListener(new ValueEventListener()
{
  @Override
  public void onDataChange(@NonNull final DataSnapshot dataSnapshot)
  {
    AsyncTask.execute(new Runnable()
    {
      @Override
      public void run()
      {
        listFeedList.clear();

        for (DataSnapshot postSnapshot : dataSnapshot.getChildren())
        {
          TweetData tweetData = postSnapshot.getValue(TweetData.class);

          if ((tweetData != null) && (!tweetData.tweetText.equals("")))
          {
            TweetData listTweetData = new TweetData(tweetData);

            listFeedList.add(listTweetData);
          }
        }
      }
    });

    mAdapter.notifyDataSetChanged();
  }

  @Override
  public void onCancelled(@NonNull DatabaseError databaseError)
  {
  }
});


mAdapter = new TweetListAdapterFeed(listFeedList, this.getApplicationContext(), new ClickListener()
{
});

mAdapter.setHasStableIds(true);
recyclerView.setHasFixedSize(true);
recyclerView.setItemViewCacheSize(20);
recyclerView.setDrawingCacheEnabled(true);
recyclerView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(mAdapter);

Adapter:

public class TweetListAdapterFeed extends RecyclerView.Adapter<TweetListAdapterFeed.ViewHolder>
{
  private static List<TweetData> mData;
  private static Context context;
  public static FirebaseAuth mAuth;
  private static String dbFeedPath;
  private static ClickListener clickListener;

  ConfigurationBuilder cb;
  TwitterFactory tf;
  Twitter twitter;

  public TweetListAdapterFeed(@SuppressWarnings("SameParameterValue") List<TweetData> mData,
                              Context context, ClickListener clickListener)
  {
    TweetListAdapterFeed.mData = mData;
    TweetListAdapterFeed.context = context;
    TweetListAdapterFeed.clickListener = clickListener;
  }

  @NonNull
  @Override
  public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i)
  {
    dbFeedPath = context.getString(R.string.isu_feed);

    ViewHolder viewHolder = new ViewHolder(LayoutInflater.from(viewGroup.getContext())
                                           .inflate(R.layout.feed_list_item, viewGroup,
                                          false), clickListener);

    statusAsyncTask = new StatusAsyncTask(this, viewHolder, i);
    mediaAsyncTaskFeed = new MediaAsyncTaskFeed(this, viewHolder);

    return viewHolder;
  }

  @Override
  public void onBindViewHolder(@NonNull final ViewHolder viewHolder, final int i)
  {
    // Update Like and Retweet Count via AsyncTask
    statusAsyncTask.execute(mData.get(i).getTweetStatusID());

    // Tweet Media
    if (!mData.get(i).getTweetPic1().equals(""))
    {
      viewHolder.photo1.setVisibility(View.VISIBLE);
      viewHolder.photo1.setImageResource(R.drawable.loading_image);
      mediaAsyncTaskFeed.execute(mData.get(i).getTweetPic1());
    }
    else
    {
      viewHolder.photo1.setVisibility(View.GONE);
    }

    // Twitter Profile Image
    Picasso.get().load(mData.get(i).getProfileImage()).fit().into(viewHolder.profileImage);

    // Twitter Name
    viewHolder.twitterName.setText(mData.get(i).getTwitterName());

    // Twitter Handle
    String tString = context.getString(R.string.AtSymbol) + mData.get(i).getTwitterHandle();
    viewHolder.twitterHandle.setText(tString);

    // Tweet Time, converted to Time since Tweet was posted
    String timeAgo = convertDateToTimeAgo(mData.get(i).getTweetTime());
    viewHolder.tweetDate.setText(timeAgo);

    // Tweet Text
    viewHolder.tweetText.setText(mData.get(i).getTweetText());

    // Retweeted By
    if (!mData.get(i).getRetweetedBy().equals(""))
    {
      // Tweet was a Retweet
      viewHolder.retweetedBy.setText(mData.get(i).getRetweetedBy());
      viewHolder.retweetedBy.setVisibility(View.VISIBLE);
      viewHolder.imageRetweetedBy.setVisibility(View.VISIBLE);
    }
    else
    {
      // Tweet was original
      viewHolder.retweetedBy.setText("");
      viewHolder.retweetedBy.setVisibility(View.GONE);
      viewHolder.imageRetweetedBy.setVisibility(View.GONE);
    }
  }

  /*
  @Override
  public long getItemId(int position)
  {
    return position; //TweetListAdapterFeed.mData.get(position).getTweetStatusID();
  }
   */
0 Answers
Related