5

無限にスクロールすると無限のアイテムが読み込まれる可能性のあるリストビューがあります。

リストビューの各アイテムには、遅延読み込みしている1つまたは2つの画像があります。

すべてがうまく機能しますが、本当に長い間スクロールすると、logcatでこれがクラッシュします

 08-07 15:26:25.231: E/AndroidRuntime(30979): FATAL EXCEPTION: Thread-60
08-07 15:26:25.231: E/AndroidRuntime(30979): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
08-07 15:26:25.231: E/AndroidRuntime(30979):    at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
08-07 15:26:25.231: E/AndroidRuntime(30979):    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:493)
08-07 15:26:25.231: E/AndroidRuntime(30979):    at com.test.android.helper.LazyImageLoader.decodeFile(LazyImageLoader.java:171)
08-07 15:26:25.231: E/AndroidRuntime(30979):    at com.test.android.helper.LazyImageLoader.getBitmap(LazyImageLoader.java:112)
08-07 15:26:25.231: E/AndroidRuntime(30979):    at com.test.android.helper.LazyImageLoader.access$2(LazyImageLoader.java:106)
08-07 15:26:25.231: E/AndroidRuntime(30979):    at com.test.android.helper.LazyImageLoader$ImageLoader.run(LazyImageLoader.java:197)

私の怠惰な画像ローダーでは、ビットマップをに保存していWeakHashMapます。では、ガベージコレクターはビットマップを正しく収集する必要がありますか?

私の怠惰なイメージローダーはこのように動作します。

displayImage()URLとimageviewへの参照を使用してアダプターから呼び出します

public void displayImage(String url, ImageView imageView, int defaultImageResourceId){

        latestImageMetaData.put(imageView, url);

        if(weakhashmapcache.containsKey(url)){
            imageView.setImageBitmap(weakhashmapcache.get(url));
        }
        else{
            enqueueImage(url, imageView, defaultImageResourceId);
            imageView.setImageResource(defaultImageResourceId);
        }
    }

したがって、キャッシュ内に画像が見つかった場合は、直接設定します。それ以外の場合は、関数を使用してキューに入れますenqueueImage()

private void enqueueImage(String url、ImageView imageView、int defaultImageResourceId){Image image = new Image(url、imageView、defaultImageResourceId); downloadqueue.add(image); // downloadQueueは、画像が追加されるのを待つブロッキングキューです//キューがいっぱいになりそうな場合は、キューの先頭にある要素を削除します。これらはとにかく表示されないためですIterator iterator = downloadQueue.iterator(); while(iterator.hasNext()&& downloadQueue.remainingCapacity()<80){downloadQueue.remove(iterator.next()); }}

And my image loader thread is this - 

class ImageLoader extends Thread {

    public void run() {
        Image firstImageInQueue;

        try {
            while((firstImageInQueue = downloadQueue.take()) != SHUTDOWN_TOKEN)
            {
                Bitmap imageBitmap = getBitmap(firstImageInQueue.url);

                if(imageBitmap != null){
                    weakhashmap.put(firstImageInQueue.url, imageBitmap);
                    BitmapDisplayer displayer = new BitmapDisplayer(imageBitmap, firstImageInQueue.imageView, firstImageInQueue.url, firstImageInQueue.defaultImageResourceId);
                    Activity activity = (Activity)firstImageInQueue.imageView.getContext();
                    activity.runOnUiThread(displayer);
                }
            }
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
        finally {
            imageLoaderTerminated = true;
        }
    } 
}

getBitmap()URLスケールから画像をフェッチし、それをビットマップオブジェクトにデコードするだけです。BitmapDisplayerUIスレッドで画像から画像ビューへの設定を行う単なるRunnableです。

私は何が間違っているのですか?

4

2 に答える 2

1

それは悪夢であり、ここでの昼夜の研究の後、他の人に役立つかもしれないいくつかのポイントがあります。

すべてのビットマップをキャッシュに保存しないでください。ディスクキャッシュとメモリキャッシュの間でスワップし続けます。保存するビットマップの数は、呼び出しによって取得するヒープ制限によって異なります。

int memClass = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)) .getMemoryClass();

キャッシュのLruCache代わりに使用しました。サポートパッケージで利用可能です。既存の実装をに置き換えるのは非常に簡単です。Androidには、キャッシュビットマップに関する美しいドキュメントもあります。WeakHashMapLruCacheWeakHashMapLruCache

Jake Wharton'sDiskLruCacheは、ディスクキャッシュを管理するための優れた方法です。

必要がない場合は、巨大なビットマップをダウンロードしないでください。あなたのニーズにちょうど合うのにちょうど良いサイズを手に入れてみてください。

BitmapFactory.Optionsを使用すると、メモリキャッシュにより多くの画像を保持するために、画質とのトレードオフを行うことができます。

他にできることがあれば、追加してください。

于 2012-11-27T09:17:13.503 に答える
1

ユニバーサルイメージローダーをお試しください

これはオープンソースプロジェクトであり、その使用方法に関するブログ投稿があります。私はすでにいくつかのプロジェクトでそれを使用しており、大きな長いリストでも問題はありません。

楽しみ!!

于 2012-10-11T19:55:56.887 に答える