0

私はAndroidで作業しており、Imagedownloaderクラスを使用して画像をダウンロードし、リストビュー項目の画像ビューに順番に設定しています。

しかし、リストビューを連続してスクロールしているときに Outoffmemory 例外が発生することがあります。

例外は次のとおりです。

   01-28 15:30:47.580: E/AndroidRuntime(3723): FATAL EXCEPTION: main
   01-28 15:30:47.580: E/AndroidRuntime(3723): java.lang.OutOfMemoryError
   01-28 15:30:47.580: E/AndroidRuntime(3723):  at       android.graphics.Bitmap.nativeCreate(Native Method)
   01-28 15:30:47.580: E/AndroidRuntime(3723):  at android.graphics.Bitmap.createBitmap(Bitmap.java:605)
   01-28 15:30:47.580: E/AndroidRuntime(3723):  at android.graphics.Bitmap.createBitmap(Bitmap.java:551)
   01-28 15:30:47.580: E/AndroidRuntime(3723):  at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:437)
  01-28 15:30:47.580: E/AndroidRuntime(3723):   at android.graphics.BitmapFactory.finishDecode(BitmapFactory.java:618)
  01-28 15:30:47.580: E/AndroidRuntime(3723):   at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:593)
  01-28 15:30:47.580: E/AndroidRuntime(3723):   at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:445)
  01-28 15:30:47.580: E/AndroidRuntime(3723):   at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:773)
  01-28 15:30:47.580: E/AndroidRuntime(3723):   at android.content.res.Resources.loadDrawable(Resources.java:1968)
  01-28 15:30:47.580: E/AndroidRuntime(3723):   at android.content.res.Resources.getDrawable(Resources.java:677)
  01-28 15:30:47.580: E/AndroidRuntime(3723):   at com.lt.appmedia.customise.SpeakersAdapter.getView(SpeakersAdapter.java:118)
  01-28 15:30:47.580: E/AndroidRuntime(3723):   at android.widget.AbsListView.obtainView(AbsListView.java:2197)
  01-28 15:30:47.580: E/AndroidRuntime(3723):   at android.widget.ListView.makeAndAddView(ListView.java:1774)
  01-28 15:30:47.580: E/AndroidRuntime(3723):   at android.widget.ListView.fillDown(ListView.java:672)
  01-28 15:30:47.580: E/AndroidRuntime(3723):   at android.widget.ListView.fillGap(ListView.java:636)
  01-28 15:30:47.580: E/AndroidRuntime(3723):   at android.widget.AbsListView.trackMotionScroll(AbsListView.java:5259)
  01-28 15:30:47.580: E/AndroidRuntime(3723):   at android.widget.AbsListView$FlingRunnable.run(AbsListView.java:4467)
  01-28 15:30:47.580: E/AndroidRuntime(3723):   at android.os.Handler.handleCallback(Handler.java:605)
  01-28 15:30:47.580: E/AndroidRuntime(3723):   at android.os.Handler.dispatchMessage(Handler.java:92)
  01-28 15:30:47.580: E/AndroidRuntime(3723):   at android.os.Looper.loop(Looper.java:137)
  01-28 15:30:47.580: E/AndroidRuntime(3723):   at android.app.ActivityThread.main(ActivityThread.java:4511)
  01-28 15:30:47.580: E/AndroidRuntime(3723):   at java.lang.reflect.Method.invokeNative(Native Method)
  01-28 15:30:47.580: E/AndroidRuntime(3723):   at java.lang.reflect.Method.invoke(Method.java:511)
  01-28 15:30:47.580: E/AndroidRuntime(3723):   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:980)
  01-28 15:30:47.580: E/AndroidRuntime(3723):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:747)
  01-28 15:30:47.580: E/AndroidRuntime(3723):   at dalvik.system.NativeStart.main(Native Method)

これを解決する方法がわかりません。

ImageDownloader クラスは

public class ImageDownloader {

private final Map<String, SoftReference<Drawable>> mCache = new HashMap<String, SoftReference<Drawable>>();
private final LinkedList<Drawable> mChacheController = new LinkedList<Drawable>();
private ExecutorService mThreadPool;
private final Map<ImageView, String> mImageViews = Collections
        .synchronizedMap(new WeakHashMap<ImageView, String>());

public static int MAX_CACHE_SIZE = 150;
public int THREAD_POOL_SIZE = 3;

private static ImageDownloader imageDownloader;


public static ImageDownloader shareInstance(){
    if(imageDownloader == null){
        imageDownloader = new ImageDownloader();
    }
    return imageDownloader;
}


/**
 * Constructor
 */
public ImageDownloader() {
    mThreadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
}

/**
 * Clears all instance data and stops running threads
 */
public void Reset() {
    ExecutorService oldThreadPool = mThreadPool;
    mThreadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
    oldThreadPool.shutdownNow();

    mChacheController.clear();
    mCache.clear();
    mImageViews.clear();
}

public void loadDrawable(final String url, final ImageView imageView,
        Drawable placeholder) {
    mImageViews.put(imageView, url);
    Drawable drawable = getDrawableFromCache(url);

    // check in UI thread, so no concurrency issues
    if (drawable != null) {
        // Log.d(null, "Item loaded from mCache: " + url);
        imageView.setBackgroundDrawable(drawable);
    } else {
        imageView.setBackgroundDrawable(placeholder);
        queueJob(url, imageView, placeholder);
    }
}

private Drawable getDrawableFromCache(String url) {
    if (mCache.containsKey(url)) {
        return mCache.get(url).get();
    }

    return null;
}

private synchronized void putDrawableInCache(String url, Drawable drawable) {
    int chacheControllerSize = mChacheController.size();
    if (chacheControllerSize > MAX_CACHE_SIZE)
        mChacheController.subList(0, MAX_CACHE_SIZE / 2).clear();

    mChacheController.addLast(drawable);
    mCache.put(url, new SoftReference<Drawable>(drawable));

}

private void queueJob(final String url, final ImageView imageView,
        final Drawable placeholder) {
    /* Create handler in UI thread. */
    final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            String tag = mImageViews.get(imageView);
            if (tag != null && tag.equals(url)) {
                if (imageView.isShown())
                    if (msg.obj != null) {
                           imageView.setBackgroundDrawable((Drawable) msg.obj);
                    } else {
  //                               imageView.setImageDrawable(placeholder);
                        imageView.setBackgroundDrawable(placeholder);
                        // Log.d(null, "fail " + url);
                    }
            }
        }
    };

    mThreadPool.submit(new Runnable() {
        @Override
        public void run() {
            final Drawable bmp = downloadDrawable(url);
            // if the view is not visible anymore, the image will be ready
            // for next time in cache
            if (imageView.isShown()) {
                Message message = Message.obtain();
                message.obj = bmp;
                // Log.d(null, "Item downloaded: " + url);

                handler.sendMessage(message);
            }
        }
    });
}

private Drawable downloadDrawable(String url) {
    try {
        InputStream is = getInputStream(url);

        Drawable drawable = Drawable.createFromStream(is, url);
        putDrawableInCache(url, drawable);
        return drawable;

    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

    return null;
}

private InputStream getInputStream(String urlString)
        throws MalformedURLException, IOException {
    URL url = new URL(urlString);
    URLConnection connection;
    connection = url.openConnection();
    connection.setUseCaches(true);
    connection.connect();
    InputStream response = connection.getInputStream();

    return response;
}
 }

そして、次の方法で ListView アイテムに画像を設定しています。

imageDownloader.loadDrawable(EventsListActivity.stylesheet.getBaseurl()+""+speaker.getPhoto(), imageView, mContext.getResources().getDrawable( R.drawable.noimage ));
4

2 に答える 2

0

に問題はありませんImageDownloaderが、あなたのリストに問題はありません。

多数の画像を含むリストを作成する場合は、いくつかの手順に従います。

  1. アイテム ビューを再利用します。これはアダプターによってサポートされており、実装が簡単です。

  2. すべての画像をローカルに保存しないでください。ビットマップが多くのスペースを占める場合は、古いものへの参照を解放し、GC にそれらを収集させる必要があります。また、リストがスクロールバックしたときに再度ダウンロードすることを忘れないでください.

于 2013-01-28T10:28:45.890 に答える
0

モバイル デバイスではリソースに制約があり、Android では特に、このようなリスト ビューで複数の画像を処理する場合に頭を悩ませます。

私は提案します:

  1. 画像を再度ダウンロードする必要がないように、画像をキャッシュするためにLRUCache を調査します。これに関する情報は、http: //android-er.blogspot.com.au/2012/07/caching-bitmaps-with-lrucache.htmlhttp://developer.android.com/reference/で見つけることができます。 android/util/LruCache.html . 古いプラットフォームをターゲットにしている場合は、サポート ライブラリにもあります。

  2. List Adapter を実装する- それが目的です。この方法では、目に見える画像を表示するためだけにリソースを使い果たしています。これと画像のダウンロードの両方について、いくつかの良い議論があります: How to display a list of images in a ListView in Android?

  3. Bitmpafactoryを使用して画像を縮小します: http://developer.android.com/reference/android/graphics/BitmapFactory.html - これにより、リソースの割り当てが過剰にならないようになります。必要な寸法/縮尺のみを使用してください。

  4. アダプター クラスをオーバーライドするときは、上記の LRUCache を使用していることを確認し、最初 にイメージがキャッシュにあるかどうかを確認し、そうでない場合はイメージをダウンロードします。これにより、画像を再取得する必要がなくなり、スクロールアップが大幅に高速化されます。

画像はトリッキーなリソースを大量に消費しますが、きちんとしたアダプター、適切なスケーリング/再サンプリング、およびキャッシュの使用により、厄介なメモリ不足エラーのない安​​定したユーザー エクスペリエンスが実現します。

于 2013-01-28T12:45:25.243 に答える