3

View Pager を使用して、アプリケーションでネットワークからダウンロードした画像を表示しています。画像の数は 5 ~ 20 です。ネットワーク操作には Volley ライブラリを使用しています。アプリは以前はあまりメモリを消費していませんでしたが、ビューページャーを追加した後、アプリは大量のメモリを消費し、このアクティビティを開くたびに、ヒープで使用されるメモリが増加します (ログメッセージから確認)。また、Eclipse メモリ アナライザーを使用して、リークがどこにあるかを確認しました。それは間違いなく、このアクティビティのビットマップと複数のインスタンスです。このアクティビティはGCされていないため、間違いなくリークがあり、いくつかの参照がこれをガベージコレクションから遠ざけています。ビューページャーの実装をここに追加しました。

public class ViewPagerAdapter extends PagerAdapter {
        Context context;

        public ViewPagerAdapter(Context context) {
            this.context = context;
        }

        @Override
        public int getCount() {
            return photoReferences.size();
        }

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

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            final ImageView im;
            final ProgressBar pb;

            View itemView = inflater.inflate(R.layout.place_photos_item, container, false);

            im = (ImageView) itemView.findViewById(R.id.placeImage);
            attributes = (TextView) itemView.findViewById(R.id.placeAttributes);
            pb = (ProgressBar) itemView.findViewById(R.id.progressBarPhoto);

            imageLoader.get(url, new ImageListener() {

                public void onErrorResponse(VolleyError arg0) {
                    im.setImageResource(R.drawable.onErrorImage); 
                }

                public void onResponse(ImageContainer response, boolean arg1) {
                    if (response.getBitmap() != null) {
                        im.startAnimation(AnimationUtils.loadAnimation(context, android.R.anim.fade_in));
                        im.setImageBitmap(response.getBitmap());
                        pb.setVisibility(View.GONE);
                    } 
                }
            });

            ((ViewPager) container).addView(itemView);

            return itemView;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            ((ViewPager) container).removeView((RelativeLayout) object);
        }

    }

また、screenBytes (screenWidth * screenHeight * 4) の 3 倍のサイズのビットマップ キャッシュを使用しています。4.3 を実行している Nexus 4 でテストしていますが、このデバイスではヒープ サイズが非常に大きいため、OOM 例外が発生することはありませんが、アクティビティを開くと、アプリは 100 MB を超えるメモリを使用する可能性があります (ほとんどのデバイスではクラッシュします)。何度も何度も、以前は何があっても約 16 ~ 20 MB のメモリを消費していました。これがキャッシュコードです。

public class BitmapCache extends LruCache<Object, Object> implements ImageCache {
        public BitmapCache(int maxSize) {
            super(maxSize);
        }

        @Override
        public Bitmap getBitmap(String url) {
            return (Bitmap) get(url);
        }

        @Override
        public void putBitmap(String url, Bitmap bitmap) {
            put(url, bitmap);
        }
    }

誰かがリークをキャッチするために何をすべきか教えてもらえますか? View Pager または Volley の使用法に問題はありますか? Pager の移行にも満足していません。少し遅れていますが、それは関係していますか?

更新: これは MAT のスクリーンショットです。リークの可能性があります。これは、Volley ライブラリを使用するすべてのアクティビティにあります。私はたくさん読んできましたが、問題を解決できませんでした。ボレーがリークを引き起こしているのでしょうか、それとも私が何かひどく間違ったことをしているのでしょうか?

4

4 に答える 4

2

Viewpager と Imageviewsを使用していると思います

画像ビューについては、最新のVolley Imageloading (大きなサイズの画像に非常に役立つ) のような強力な画像のダウンロードおよびキャッシュ ライブラリを使用して、画像の読み込み機能を効率的に改善しています。

Viewpager については、効率的なアダプターFragmentStatePagerAdapterを使用する必要があります。このバージョンのページャーは、多数のページがある場合に便利で、リスト ビューのように機能します。ページがユーザーに表示されない場合、フラグメント全体が破棄され、そのフラグメントの保存された状態のみが保持されます。これにより、ページャーは、FragmentPagerAdapter と比較して、訪問した各ページに関連付けられたメモリをはるかに少なく保持できますが、ページを切り替えるときにオーバーヘッドが増える可能性があります。

FragmentPagerAdapter を使用する前によく考えてください。なぜなら、FragmentPagerAdapter はフラグメント全体をメモリに格納し、ViewPager で大量のフラグメントが使用されるとメモリ オーバーヘッドが増加する可能性があるためです。その兄弟とは対照的に、FragmentStatePagerAdapter はフラグメントの savedInstanceState のみを格納し、フォーカスを失うとすべてのフラグメントを破棄します。したがって、動的フラグメント (ウィジェットを含むフラグメントなど) を使用する必要がある場合は、FragmentStatePagerAdapter を使用する必要があります。これらのデータは、savedInstanceState に格納される可能性があるためです。また、多数のフラグメントがあってもパフォーマンスには影響しません。反対に、フラグメント全体をメモリに格納する必要がある場合は、兄弟の FragmentPagerAdapter を使用する必要があります。フラグメント全体がメモリに保持されると言うとき、それは、そのインスタンスが破棄されず、メモリ オーバーヘッドが発生することを意味します。したがって、ViewPager のフラグメント数が少ない場合にのみ、FragmentPagerAdapter を使用することをお勧めします。インスタンスが格納されるオブジェクトが大量にないため、フラグメントが静的であるとさらに良いでしょう。これにより、Android FragmentPagerAdapter と FragmentStatePagerAdapter の違いが明確になることを願っています。

Google androidギャラリーアプリの例を学び、画像ビューの読み込みアニメーションを使用して優れたユーザー エクスペリエンスを実現してください。

これにより、ヒープ増加の問題が解決されることを願っています。

クレジット: FragmentPagerAdapter と FragmentStatePagerAdapter の比較

于 2013-11-13T04:42:34.550 に答える
0

Volley の新しいバージョンをチェックアウトする必要があります。古いバージョンはリークの問題を引き起こしました。古いバージョンでは、Volley には 4 つのスレッド do request があり、それぞれが request を保持し、request は listener の強い参照を保持し、応答リスナーは ImageView で何かを行い、ImageView は Activity コンテキストを保持します。したがって、すべてのビューがリークされます。MAT を使用select * from instanceof android.app.Activityすると、Activity がリークされていることがわかります。

Volley の新しいバージョンでは、この問題が修正されています。 ここでチェックしてください

そして、これを使用すると、リークされたアクティビティ、leakcanaryを見つけるのに役立ちます

于 2015-07-19T03:47:26.337 に答える