Recyclerview péniblement lent à charger des images cachées de Picasso

j'ai implémenté un RecyclerView qui contient principalement des images qui se chargent à travers Picasso. Mon problème est que dès que je fais défiler vers le bas ou vers le haut de la vue, l'image placeholder apparaît pour environ. une seconde avant elle est remplacée par l'image réelle. Il déforme très bien, mais il est pratiquement inutilisable. Cela se produit chaque fois que quelque chose sort de l'écran.

Picasso cache clairement les images sur le disque, car elles se chargent plus rapidement que la première temps de chargement, mais ils sont certainement instantanément recharger à partir du cache. Qu'ai-je mettre en œuvre de façon incorrecte?

mon code adaptateur:

public class ExploreAdapter extends RecyclerView.Adapter<ExploreAdapter.ExploreViewHolder> {

    private List<ExploreItem> exploreItemList;
    private Context mContext;
    private int deviceWidth = PrefUtils.getDeviceWidth();

    public ExploreAdapter(Context context, List<ExploreItem> exploreItemList){
        this.mContext = context;
        this.exploreItemList = exploreItemList;
    }

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

    @Override
    public void onBindViewHolder(ExploreViewHolder exploreViewHolder, int i){
        ExploreItem item = exploreItemList.get(i);
        exploreViewHolder.getvTitle().setText(item.getTitle());
        exploreViewHolder.getvUsername().setText(item.getUsername());
        exploreViewHolder.getvNumLikes().setText(item.getNbOfLikes());

        Picasso.with(mContext).load(item.getMediaLocation().trim())
                .resize(deviceWidth, deviceWidth)
                .centerCrop()
                .placeholder(R.drawable.profile_background)
                .into(exploreViewHolder.getvImage());

        Picasso.with(mContext).load(item.getUserProfilePicUrl().trim())
                .placeholder(R.drawable.profile_picture)
                .into(exploreViewHolder.getvProfilePic());
    }

    @Override
    public ExploreViewHolder onCreateViewHolder(ViewGroup viewGroup, int i){
        View itemView = LayoutInflater.
                from(viewGroup.getContext()).
                inflate(R.layout.explore_item, viewGroup, false);

        return new ExploreViewHolder(itemView);
    }

    public static class ExploreViewHolder extends RecyclerView.ViewHolder{
        private TextView  vTitle,
                          vUsername,
                          vNumLikes;

        private SquareImage vImage;
        private ImageView vProfilePic;

        public ExploreViewHolder(View v){
            super(v);
            this.vTitle = (TextView) v.findViewById(R.id.explore_item_title);
            this.vUsername = (TextView) v.findViewById(R.id.explore_item_username);
            this.vNumLikes = (TextView) v.findViewById(R.id.explore_item_number_likes);
            this.vImage = (SquareImage) v.findViewById(R.id.explore_item_image);
            this.vProfilePic = (ImageView) v.findViewById(R.id.explore_item_profile_picture);
        }

        public TextView getvTitle() {
            return vTitle;
        }

        public TextView getvUsername() {
            return vUsername;
        }

        public ImageView getvProfilePic() {
            return vProfilePic;
        }

        public SquareImage getvImage() {
            return vImage;
        }

        public TextView getvNumLikes() {
            return vNumLikes;
        }

        public void setvImage(SquareImage vImage) {
            this.vImage = vImage;
        }

        public void setvNumLikes(TextView vNumLikes) {
            this.vNumLikes = vNumLikes;
        }

        public void setvProfilePic(ImageView vProfilePic) {
            this.vProfilePic = vProfilePic;
        }

        public void setvTitle(TextView vTitle) {
            this.vTitle = vTitle;
        }

        public void setvUsername(TextView vUsername) {
            this.vUsername = vUsername;
        }
    }
}

Toute aide est appréciée.

44
demandé sur Vivek Barai 2014-11-11 05:28:16

7 réponses

paramètres de réglage de recyclerView comme ci-dessous résolu mon problème de bégaiement:

recyclerView.setHasFixedSize(true);
recyclerView.setItemViewCacheSize(20);
recyclerView.setDrawingCacheEnabled(true);
recyclerView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);

j'espère que cela aide quelqu'un d'autre aussi.

61
répondu ergunkocak 2016-04-28 15:23:28

utiliser fit() .

Picasso.with(context)
        .load(file)
        .fit()
        .centerCrop()
        .into(imageView);

le fit() redimensionne l'image pour l'adapter aux limites du imageView . Cela ne charge pas l'image complète et lisse le défilement.

25
répondu Mangesh 2016-01-08 18:08:54

j'ai mélangé la réponse de @ergunkocak et @Mangesh Ghotage, en utilisant ce grand travail:

recyclerView.setHasFixedSize(true);
recyclerView.setItemViewCacheSize(20);
recyclerView.setDrawingCacheEnabled(true);

et ceci sur chaque image:

Picasso.with(context)
        .load(file)
        .fit()
        .into(imageView);

de plus, vous pouvez configurer Picasso pour utiliser une seule instance comme celle-ci:

Picasso.setSingletonInstance(picasso);

et finalement activer les indicateurs de cache vous donnera des indices sur ce qui va mal:

Picasso  
    .with(context)
    .setIndicatorsEnabled(true);

plus d'informations sur Picasso

6
répondu lisandro101 2016-09-30 18:32:56

j'ai rencontré ce problème récemment, et oui, vous avez raison. Picasso est une bonne bibliothèque pour afficher des images de sdcard, mais il a quelques problèmes concernant la cache si vous allez chercher des images en ligne, c'est pourquoi vous voyez une image de support de place lors de la scrolling. J'ai essayé différentes choses et le problème n'a pas été résolu.

il y a une bibliothèque alternative i.e." AQuery " qui est très bonne pour récupérer et mettre en cache des images du réseau.

http://code.google.com/p/android-query /

les principaux avantages de la requête AQuery/Android est que vous pouvez effacer la cache, aucun retard lors du défilement et tout à fait efficace pour la mise en cache des images et de ne pas montrer des images de support de place lors du défilement.

j'ai résolu mon problème en retirant picaaso et en utilisant Aquery. C'est juste un remplacement d'une ligne et vous en avez fini avec votre problème.

(new AQuery(mContext)).id(exploreViewHolder.getvProfilePic()).image(item.getUserProfilePicUrl().trim(), true, true, device_width, R.drawable.profile_background, aquery.getCachedImage(R.drawable.profile_background),0);

en plus vous pouvez facilement passer de picasso à AQuery car il n'y a pas de telle chose qui est disponible dans picasso mais pas dans AQuery et la syntaxe est presque la même. Donc je vous recommande D'utiliser AQuery, jusqu'à ce que cela soit réparé par picasso.

3
répondu Faizan Tariq 2015-08-07 18:57:44

Je ne peux pas vérifier l'exactitude de cette solution, mais je faisais face à ce problème aussi bien et approché en suivant cette idée:

@Override
public void onBindViewHolder(ViewHolder viewHolder, final int i) {

...

if(mImageView.getDrawable == null()){
     Picasso.with(context)
            .load(path)
            .error(errorResId)
            .tag(tag)
            .into(mImageView);
}

...  

}

il est prévu d'interdire à Picasso de charger quoi que ce soit à moins que L'ImageView n'ait rien à afficher.

1
répondu Jorge Antonio Díaz-Benito 2014-11-13 09:31:48

Picasso cache automatiquement des images en deux niveaux:

  • cache disque (ce n'est en fait pas dans picasso mais dans la couche réseau que picasso utilise)
  • mémoire cache

ils sont Bot initialisés par défaut qui suit la plupart des applications.

quand le cache mémoire devient trop grand le bitmap le plus ancien utilisé est retiré du cache mémoire (qui par défaut est 1/7 de la espace tas disponible).

je pense que ce qui se passe ici est que vous êtes proche de la limite de mémoire du cache et donc les images sont décodées à nouveau chaque fois que vous en avez besoin.

voir ici: Android Picasso Configurer LruCache Taille

mais je déconseille d'augmenter la taille du cache mémoire à moins que vous ne re-dimensionniez les images à la taille réelle que vous utilisez..

je pense que le le problème avec votre code est ceci:

.resize(deviceWidth, deviceWidth)

êtes-vous sûr que vous avez vraiment besoin d'une image de cette taille? Que stockez-vous dans les Préfutils ? fait-il mis à jour lorsque l'appareil tourne? (paysage vs portrait)

si vous avez besoin d'images plus petites essayer de passer la taille réelle de l'image que vous allez utiliser. Si vous ne savez pas (calculé à l'exécution avec la mise en page) faites avec une approximation ou écrivez votre code pour obtenir la taille réelle (j'écris habituellement des classes personnalisées étendant ImageView pour ces trucs).

si vous avez vraiment besoin des images de cette taille, augmentez simplement la taille du cache (voir le lien ci-dessus) et vous devriez être prêt à y aller.

1
répondu Daniele Segato 2017-05-23 11:54:44

il suffit d'utiliser noPlaceholder attribut.

-2
répondu pichon 2016-09-14 11:52:37