Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Picasso Recyclerview Image downloading slow

I have endless recyclerview that almost mimics Instagram list/feeds. Where Image is loading into full screen width Imageview. I am using Picasso to load images. Here is my code:

public class HomeAdapter extends RecyclerView.Adapter {

Context context;

private Contract contract;

List<Feed> feeds;

static final int ITEM_TYPE_HEADER = 0;

static final int ITEM_TYPE_LOAD_MORE = 1;

static final int ITEM_TYPE_DESIGN = 2;

public HomeAdapter(Context context, List<Feed> feeds) {
    this.context = context;
    this.feeds = feeds;
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    LayoutInflater inflater = LayoutInflater.from(parent.getContext());
    View row;
    if (viewType == ITEM_TYPE_HEADER) {
        row = inflater.inflate(R.layout.list_item_home_header, parent, false);
        return new HeaderHolder(row);
    } else if (viewType == ITEM_TYPE_LOAD_MORE) {
        row = inflater.inflate(R.layout.list_item_load_more, parent, false);
        return new LoadMoreHolder(row);
    } else if (viewType == ITEM_TYPE_DESIGN) {
        row = inflater.inflate(R.layout.list_item_feed_home, parent, false);
        return new DesignItemHolder(row);
    }
    return null;
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
    Feed feed = feeds.get(position);
    if (holder instanceof HeaderHolder) {
        HeaderHolder headerHolder = (HeaderHolder) holder;
        Header header = (Header) feed;
        headerHolder.tvTitle.setText(header.getTitle());
        headerHolder.tvDescription.setText(header.getDescription());

    } else if (holder instanceof LoadMoreHolder) {
        LoadMoreHolder loadMoreHolder = (LoadMoreHolder) holder;
        LoadMore loadMore = (LoadMore) feed;
        if(loadMore.getType() == LOAD_MORE_TYPE_PROGRESS) {
            loadMoreHolder.pbLoadMore.setVisibility(View.VISIBLE);
            loadMoreHolder.rlMessageRetry.setVisibility(View.GONE);
        } else {
            loadMoreHolder.pbLoadMore.setVisibility(View.GONE);
            loadMoreHolder.rlMessageRetry.setVisibility(View.VISIBLE);
            if(StringUtils.isValid(loadMore.getTitle())) {
                loadMoreHolder.tvTitle.setText(loadMore.getTitle());
                loadMoreHolder.tvTitle.setVisibility(View.VISIBLE);
            } else
                loadMoreHolder.tvTitle.setVisibility(View.GONE);

            if(StringUtils.isValid(loadMore.getDescription())) {
                loadMoreHolder.tvDescription.setText(loadMore.getDescription());
                loadMoreHolder.tvDescription.setVisibility(View.VISIBLE);
            } else
                loadMoreHolder.tvDescription.setVisibility(View.GONE);
        }

        loadMoreHolder.btnRetry.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(contract != null)
                    contract.onRetryLoadMoreClick();
            }
        });

    } else if (holder instanceof DesignItemHolder) {
        final DesignItemHolder designItemHolder = (DesignItemHolder) holder;
        final DesignFeed designFeed = (DesignFeed) feed;
        String title = getFeedTitle(designFeed.getDesignCategory().getTitle(), designFeed.getEvent().getTitle());
        designItemHolder.tvCategory.setText(StringUtils.toUpperCaseSentence(designFeed.getDesignCategory().getTitle()));
        designItemHolder.tvDate.setText(DateTimeUtils.formatTime(designFeed.getDate()));
        designItemHolder.tvTitle.setText(StringUtils.toUpperCaseSentence(title));
        designItemHolder.tvBrand.setText(getBrandTitle(designFeed.getBrand().getTitle()));

        if(StringUtils.isValid(designFeed.getShopLink())) {
            designItemHolder.tvShop.setVisibility(View.VISIBLE);
            if(StringUtils.isValid(designFeed.getPrice())) {
                designItemHolder.tvPrice.setVisibility(View.VISIBLE);
                designItemHolder.tvPrice.setText(designFeed.getPrice() + " PKR");
            } else
                designItemHolder.tvPrice.setVisibility(View.GONE);

            designItemHolder.tvShop.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if(contract != null)
                        contract.onOpenShopLink(designFeed.getShopLink());
                }
            });
        }
        else {
            designItemHolder.tvPrice.setVisibility(View.GONE);
            designItemHolder.tvShop.setVisibility(View.GONE);
        }

        showFeedImage(designFeed, designItemHolder.ivThumbnail, designItemHolder.progressBar);

        Picasso.get()
                .load(designFeed.getDesignCategory().getThumbnail())
                .transform(new CircleTransform())
                .placeholder(new ColorDrawable(ContextCompat.getColor(context, R.color.colorGreyLight)))
                .into(designItemHolder.ivCategory);

        designItemHolder.ivThumbnail.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(contract != null)
                    contract.onDesignFeedClick(designFeed);
            }
        });

        designItemHolder.tvCategory.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(contract != null)
                    contract.onDesignCategoryClick(designFeed.getDesignCategory());
            }
        });

        designItemHolder.ivCategory.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(contract != null)
                    contract.onDesignCategoryClick(designFeed.getDesignCategory());
            }
        });

        designItemHolder.tvTitle.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(contract != null)
                    contract.onDesignCategoryClick(designFeed.getDesignCategory());
            }
        });

        designItemHolder.tvBrand.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(contract != null)
                    contract.onBrandClick(designFeed.getBrand());
            }
        });

        designItemHolder.ibFavourite.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(contract != null)
                    contract.onFavouriteClick(designFeed);
            }
        });

        designItemHolder.ibShare.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(contract != null)
                    contract.onShareClick(designFeed);
            }
        });

        designItemHolder.ibDownload.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(contract != null)
                    contract.onDownloadClick(designFeed);
            }
        });
    }
}

private void showFeedImage(final DesignFeed designFeed, final ImageView ivThumbnail, final ProgressBar progressBar) {
    Picasso.get()
            .load(designFeed.getThumbnail())
            .placeholder(new ColorDrawable(ContextCompat.getColor(context, R.color.colorGreyLight)))
            .networkPolicy(NetworkPolicy.OFFLINE)
            .into(ivThumbnail, new Callback() {
                @Override
                public void onSuccess() {
                }

                @Override
                public void onError(Exception e) {
                    //Try again online if cache failed
                    Picasso.get()
                            .load(designFeed.getThumbnail())
                            .placeholder(new ColorDrawable(ContextCompat.getColor(context, R.color.colorGreyLight)))
                            .into(ivThumbnail, new Callback() {
                                @Override
                                public void onSuccess() {
                                }

                                @Override
                                public void onError(Exception e) {

                                }
                            });
                }
            });
}

@Override
public int getItemViewType(int position) {
    Feed feed = feeds.get(position);
    if (feed instanceof Header)
        return ITEM_TYPE_HEADER;
    else if (feed instanceof LoadMore)
        return ITEM_TYPE_LOAD_MORE;
    else if (feed instanceof DesignFeed)
        return ITEM_TYPE_DESIGN;
    else
        return super.getItemViewType(position);
}

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

public void insertFeedAtStart(Feed feed) {
    feeds.add(0, feed);
    notifyDataSetChanged();
}

public void updateFeeds(ArrayList<Feed> mFeeds) {
    feeds.addAll(mFeeds);
    notifyDataSetChanged();
}

public void addLoadMoreItem(Feed loadMoreFeed) {
    feeds.add(loadMoreFeed);
    notifyItemInserted(getItemCount() - 1);
}

public void removeItem(int index) {
    feeds.remove(index);
    notifyDataSetChanged();
}

private class DesignItemHolder extends RecyclerView.ViewHolder {
    TextView tvTitle, tvCategory, tvBrand, tvDate, tvPrice, tvShop;
    ImageView ivCategory, ivThumbnail;
    ImageButton ibFavourite, ibShare, ibDownload;
    ProgressBar progressBar;

    DesignItemHolder(View itemView) {
        super(itemView);
        tvTitle = itemView.findViewById(R.id.tvTitle);
        tvCategory = itemView.findViewById(R.id.tvCategory);
        tvBrand = itemView.findViewById(R.id.tvBrand);
        tvDate = itemView.findViewById(R.id.tvDate);
        ivCategory = itemView.findViewById(R.id.ivCategory);
        ivThumbnail = itemView.findViewById(R.id.ivThumbnail);
        tvPrice = itemView.findViewById(R.id.tvPrice);
        tvShop = itemView.findViewById(R.id.tvShop);
        ibFavourite = itemView.findViewById(R.id.ibFavourite);
        ibShare = itemView.findViewById(R.id.ibShare);
        ibDownload = itemView.findViewById(R.id.ibDownload);
        progressBar = itemView.findViewById(R.id.progressBar);
    }
}

private class HeaderHolder extends RecyclerView.ViewHolder {
    TextView tvTitle, tvDescription;
    HeaderHolder(View itemView) {
        super(itemView);
        tvTitle = itemView.findViewById(R.id.tvTitle);
        tvDescription = itemView.findViewById(R.id.tvDescription);
    }
}

private class LoadMoreHolder extends RecyclerView.ViewHolder {
    ProgressBar pbLoadMore;
    RelativeLayout rlMessageRetry;
    TextView tvTitle, tvDescription;
    AppCompatButton btnRetry;

    LoadMoreHolder(View itemView) {
        super(itemView);
        pbLoadMore = itemView.findViewById(R.id.pbLoadMore);
        rlMessageRetry = itemView.findViewById(R.id.rlMessageRetry);
        tvTitle = itemView.findViewById(R.id.tvTitle);
        tvDescription = itemView.findViewById(R.id.tvDescription);
        btnRetry = itemView.findViewById(R.id.btnRetry);
    }
}

public void setContract(Contract contract) {
    this.contract = contract;
}

public interface Contract {

    void onDesignCategoryClick(DesignCategory designCategory);

    void onDesignFeedClick(DesignFeed designCategory);

    void onBrandClick(Brand brand);

    void onRetryLoadMoreClick();

    void onShopClick(String shopLink);

    void onFavouriteClick(DesignFeed designFeed);

    void onShareClick(DesignFeed designFeed);

    void onDownloadClick(DesignFeed designFeed);

    void onOpenShopLink(String shopLink);
}

}

Average image size is 80-100 kbs. But image download time is too slow. It almost takes 3-4 seconds to download an image. On the other hand when images are loading from cache it obviously loads an image in no time. I get 15 items from server to load into recyclerview which means 15 images would be downloading in parallel. But still it is quite slow as compared to Instagram or Facebook feeds.

Can anyone guide me about the correct technique to make it as fast as possible, so that when user scrolls down the list images should be already loaded instead him waiting for image to load?

like image 610
Nouman Bhatti Avatar asked Jan 17 '26 23:01

Nouman Bhatti


1 Answers

Actually, I have been using the lib for a long time without any networking issue. I tried to analyze the code and found out followings:

  1. The problem could be the transformation Since lib first transforms incoming image then display, Please refer this part

    Picasso.get()

        .load(designFeed.getDesignCategory().getThumbnail())
        .transform(new CircleTransform())
        .placeholder(new ColorDrawable(ContextCompat.getColor(context, 
         R.color.colorGreyLight)))
        .into(designItemHolder.ivCategory);
    

Advice: if you are trying to show image in circular view. Then use CircularImageView, do not free I/O.

  • Check the performance with other a little powerful devices than yours

EDIT

  • Check your phone for network usage, which app is consuming, how much megabytes, Since some applications silently use your network in the background

  • Why it is fast in your browser? Because your browser is not doing any extra operation on the image

like image 99
Jasurbek Avatar answered Jan 19 '26 15:01

Jasurbek



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!