11

SD カードから画像を読み込んで全画面モードで表示しているときにメモリ不足エラーが発生したため、Universal Image Loader を備えた ViewPager をギャラリーのようなインターフェイスの代替として使用できるかどうか、または使用する必要があるかどうかはよくわかりません。数に関係なく、GridView では問題なく動作しますが、ビュー ページャーで画像を表示している間、各ビットマップは大量のメモリを消費し続け、10 個ほどの画像の後、メモリ不足エラーが発生します。

Universal Image Loader での作業中にメモリ不足エラーに関連してここに投稿されたほとんどすべての質問を見てきましたが、それぞれの質問で、原因として構成エラーがありました。

間違った構成を使用しているのか、それとも何を使用しているのかはわかりませんが、多くの時間を無駄にしてしまい、行き詰まっています。ヘルプ/アドバイスをいただければ幸いです。

ImageLoader の構成:

ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
            .memoryCache(new WeakMemoryCache())
            .denyCacheImageMultipleSizesInMemory()
            .discCacheFileNameGenerator(new Md5FileNameGenerator())
            .imageDownloader(new ExtendedImageDownloader(getApplicationContext()))
            .tasksProcessingOrder(QueueProcessingType.LIFO)
//          .enableLogging() // Not necessary in common
            .build();

表示画像オプションは次のとおりです。

options = new DisplayImageOptions.Builder()
            .showImageForEmptyUri(R.drawable.image_for_empty_url)
            .resetViewBeforeLoading()
            .imageScaleType(ImageScaleType.IN_SAMPLE_INT)
            .bitmapConfig(Bitmap.Config.RGB_565)
            .displayer(new FadeInBitmapDisplayer(300))
            .build();

ライブラリで提供されたサンプル プロジェクトを使用していますが、これらの設定も機能せず、しばらくするとクラッシュします。私の推測では、表示されていないビューからビットマップをリサイクルする必要がある特定のコールバックがあると思います。

編集:メモリリークであることはわかっています。表示されていないビューは、本来あるべきときに破棄されますが、メモリは解放されません。これは destroyItem コールバックの実装で、さまざまな質問に示されているヒントに従いましたが、メモリ リークはまだ見つかりません。

@Override
        public void destroyItem(View container, int position, Object object) {
//          ((ViewPager) container).removeView((View) object);
            Log.d("DESTROY", "destroying view at position " + position);
            View view = (View)object;
            ((ViewPager) container).removeView(view);
            view = null;
        }
4

7 に答える 7

5

おそらくそれを解決するための最良の実装ではありませんが、私にとってはうまくいきました。ImageView を削除するだけでは不十分なので、「destroyItem」でビットマップをリサイクルすることにしました。

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    View view = (View) object;
    ImageView imageView = (ImageView) view.findViewById(R.id.image);
    if (imageView != null) {
        Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
        bitmap.recycle();
        bitmap = null;
    }
    ((ViewPager) container).removeView(view);
    view = null;
}

これは、アクティビティを終了するときに最後の 3 つのアクティブなページを消去しませんが、GC がそれらを処理してくれることを願っています。

于 2013-03-12T17:31:21.877 に答える
4

次の提案を適用してみてください:

  1. 使用するImageScaleType.EXACTLY
  2. ディスクのキャッシュを有効にします (表示オプションで)。
  3. 最後に使ってみる.discCacheExtraOptions(maxImageWidthForDiscCache, maxImageHeightForDiscCache, CompressFormat.PNG, 0);
于 2013-02-24T16:13:56.750 に答える
2

UILとOOPを検索すると、この質問がGoogleに出てくるので、これを投稿してください。どのような構成でも OOP の問題がありました。すべての問題を解決したのは、このサンプル プロジェクトの 2 つのRecyclingImageViewクラスでしRecyclingBitmapDrawable

于 2013-03-26T08:10:46.793 に答える
1

私も同じライブラリを使用し、同じエラーが発生しました。解決策として、photoViewインスタンスを保持するためにsparseArrayを作成しました。そして、次のように使用します。

 private SparseArray<PhotoView> photoViewHolder;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
       ...

       photoViewHolder = new SparseArray<PhotoView>();
       ...
 }

private class GalleryPagerAdapter extends PagerAdapter {

@Override
public View instantiateItem(ViewGroup container, int position) { 

        PhotoView photoView = new PhotoView(container.getContext());

        ImageHolder holder = new ImageHolder();
        holder.position = position;
        holder.loaded = false;

        photoView.setTag(holder);
        photoViewHolder.put(position, photoView);

                    // I used LazyList loading
        loader.DisplayImage(items.get(position), photoView);

        // Now just add PhotoView to ViewPager and return it
        container.addView(photoView, LayoutParams.MATCH_PARENT,
                LayoutParams.MATCH_PARENT);

        return photoView;
    }

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    container.removeView((View) object);
    photoViewHolder.remove(position);
}

@Override
public boolean isViewFromObject(View view, Object object) {
    return view == object;
}

}

そして、viewPagerのリスナーを処理するには:

   pager.setOnPageChangeListener(new OnPageChangeListener() { 

    @Override
    public void onPageScrollStateChanged(int position) { 

    } 

    @Override
    public void onPageScrolled(int position, float arg1, int arg2) { 

    } 

    @Override
    public void onPageSelected(int position) { 
        if(photoViewHolder.get(position) != null) {
            ImageHolder holder = (ImageHolder)photoViewHolder.get(position).getTag();
            // Do something...
        }
    } 
});

お役に立てれば...

于 2013-03-07T13:48:54.440 に答える
0

githubの問題ページからkutotheの実装を使用しました。

于 2013-02-21T14:32:33.843 に答える
-1

遅いことはわかっていますが、私の答えが誰かの時間を節約するかもしれません。この問題を解決しようと何時間も費やした後 (スタック オーバーフローに関するほぼすべての回答が見つかりました)、最終的に Fresco イメージ ライブラリで解決しました。これは Facebook によって作成されたライブラリであり、主な目的はメモリを効率的に使用することです。それは本当に素晴らしく、私のメモリ不足エラーは消えました。使用することを強くお勧めします。

http://frescolib.org/

于 2016-01-21T18:35:01.687 に答える