web-dev-qa-db-ja.com

Recyclerviewが、ピカソからキャッシュされた画像の読み込みに非常に時間がかかる

私は、主にPicassoから読み込んでいる画像を含むRecyclerViewを実装しました。私の問題は、ビューを上下にスクロールするとすぐに、プレースホルダー画像が表示されることです。実際の画像に置き換えられる前の1秒。非常にスムーズにスクロールしますが、実際には使用できません。これは、何かが画面からスクロールするたびに発生します。

初期のロード時間よりも速くロードされるため、ピカソは明らかにディスクにイメージをキャッシュしていますが、キャッシュから確実に即座にリロードしています。間違って実装したものは何ですか?

私のアダプターコード:

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

どんな助けも大歓迎です。

50
charrondev

以下のようにrecyclerViewパラメータを設定すると、私のスタッターの問題が解決しました:

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

他の人にも役立つことを願っています。

67
ergunkocak

fit()を使用します。

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

fit()は、実際にimageViewの境界に収まるように画像のサイズを変更します。これは画像全体をロードせず、スクロールをスムーズにします。

27
Mangesh

@ergunkocakと@Mangesh Ghotageからの回答を混ぜて、これをうまく使っています:

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

そして、これはすべての画像で:

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

さらに、次のような単一のインスタンスを使用するようにPicassoを設定できます。

Picasso.setSingletonInstance(picasso);

最後に、キャッシュインジケーターを有効にすると、何が問題なのかを知る手がかりが得られます。

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

ピカソの詳細

8
lisandro101

私は最近この問題に遭遇しました、はい、あなたは正しいです。 Picassoはsdcardからの画像を表示するのに適したライブラリですが、画像をオンラインで取得する場合、キャッシュ中にプレースホルダーの画像が表示されるので、キャッシュに関していくつかの問題があります。別のことを試してみましたが、問題は解決しませんでした。

ネットワークから画像を取得してキャッシュするのに非常に適した代替ライブラリ、つまり「AQuery」があります。

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

AQuery/Android Queryの主な利点は、キャッシュをクリアできることです。スクロール中に遅延がなく、画像をキャッシュし、スクロール中にプレースホルダー画像を表示しません。

Picaasoを削除し、Aqueryを使用して問題を解決しました。これはたった1行の置換であり、問​​題は完了です。

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

それに加えて、ピカソからAQueryに使用できるものはないが、AQueryにはないものがあり、構文はほとんど同じなので、ピカソからAQueryに簡単に移行できます。したがって、これがpicassoで修正されるまで、AQueryを使用することをお勧めします。

3
Faizan Tariq

私はこの解決策の正しさを検証することはできませんが、私はこの問題に直面しており、この考えに従ってそれに取り組みました:

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

...

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

ImageViewに表示するものがない限り、Picassoが何かをロードすることを禁止することを目的としています。

Picassoは、2つのレベルで画像を自動的にキャッシュします。

  • ディスクキャッシュ(これは実際にはピカソではなく、ピカソが使用するネットワーク層にあります)
  • メモリキャッシュ

これらは、ほとんどのアプリケーションに適したデフォルトで初期化されたボットです。

メモリキャッシュが大きくなりすぎると、使用されている最も古いビットマップがメモリキャッシュから削除されます(デフォルトでは、使用可能なヒープスペースの1/7です)。

ここで起こっているのは、キャッシュのメモリ制限に近づいているため、画像が必要になるたびに画像が再度デコードされると思います。

こちらをご覧ください: Android Picasso Configure LruCache Size

ただし、実際に画像のサイズを実際のサイズに変更していない限り、メモリキャッシュサイズを増やすことをお勧めします。

あなたのコードの問題はこれだと思います:

.resize(deviceWidth, deviceWidth)

本当にそのサイズの画像が必要ですか? PrefUtilsには何を保存していますか?デバイスが回転すると更新されますか? (横向きvs縦向き)

より小さい画像が必要な場合は、使用する画像の実際のサイズをサイズ変更して渡してください。知らない場合(実行時にレイアウトを計算)、近似を行うか、実際のサイズを取得するためにコードを記述します(通常、これらのためにImageViewを拡張するカスタムクラスを記述します)。

そのサイズの画像が本当に必要な場合は、キャッシュサイズを増やしてください(上記のリンクを参照)。

1
Daniele Segato

この質問の最良の答えは、ラウンド画像ビューを使用しないでください。単純な画像ビューで変換を使用するだけです。ラウンド画像ビューのため、アプリケーションは単純な画像ビューを使用して変換を設定するだけで多くのメモリを消費します この変換を使用

0
Rana Asad