Ленивая загрузка изображений в ListView

1824

Я использую ListView для отображения некоторых изображений и титров, связанных с этими изображениями. Я получаю изображения из Интернета. Есть ли способ ленивой загрузки изображений, поэтому, пока отображается текст, пользовательский интерфейс не заблокирован и изображения отображаются по мере их загрузки?

Общее количество изображений не фиксировано.

  • 8
    Вы можете использовать AsyncImageView GreenDroid . Просто позвоните setUrl .
  • 6
    Я использовал это. Это прекрасная реализация. Плохая новость в том, что AsyncImageView является частью большого проекта GreenDroid, который увеличивает размер вашего приложения даже в том случае, если вам нужен только AsyncImageView. Также, похоже, проект GreenDroid не обновляется с 2011 года.
Показать ещё 10 комментариев
Теги:
image
url
listview
universal-image-loader

38 ответов

1018
Лучший ответ

Вот то, что я создал для хранения изображений, которые в настоящее время отображается моим приложением. Обратите внимание, что используемый здесь объект "Журнал" - это моя настраиваемая оболочка вокруг конечного класса журнала внутри Android.

package com.wilson.android.library;

/*
 Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
*/
import java.io.IOException;

public class DrawableManager {
    private final Map<String, Drawable> drawableMap;

    public DrawableManager() {
        drawableMap = new HashMap<String, Drawable>();
    }

    public Drawable fetchDrawable(String urlString) {
        if (drawableMap.containsKey(urlString)) {
            return drawableMap.get(urlString);
        }

        Log.d(this.getClass().getSimpleName(), "image url:" + urlString);
        try {
            InputStream is = fetch(urlString);
            Drawable drawable = Drawable.createFromStream(is, "src");


            if (drawable != null) {
                drawableMap.put(urlString, drawable);
                Log.d(this.getClass().getSimpleName(), "got a thumbnail drawable: " + drawable.getBounds() + ", "
                        + drawable.getIntrinsicHeight() + "," + drawable.getIntrinsicWidth() + ", "
                        + drawable.getMinimumHeight() + "," + drawable.getMinimumWidth());
            } else {
              Log.w(this.getClass().getSimpleName(), "could not get thumbnail");
            }

            return drawable;
        } catch (MalformedURLException e) {
            Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
            return null;
        } catch (IOException e) {
            Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
            return null;
        }
    }

    public void fetchDrawableOnThread(final String urlString, final ImageView imageView) {
        if (drawableMap.containsKey(urlString)) {
            imageView.setImageDrawable(drawableMap.get(urlString));
        }

        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message message) {
                imageView.setImageDrawable((Drawable) message.obj);
            }
        };

        Thread thread = new Thread() {
            @Override
            public void run() {
                //TODO : set imageView to a "pending" image
                Drawable drawable = fetchDrawable(urlString);
                Message message = handler.obtainMessage(1, drawable);
                handler.sendMessage(message);
            }
        };
        thread.start();
    }

    private InputStream fetch(String urlString) throws MalformedURLException, IOException {
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpGet request = new HttpGet(urlString);
        HttpResponse response = httpClient.execute(request);
        return response.getEntity().getContent();
    }
}
  • 100
    Я думаю, что вы должны использовать SoftReferences, чтобы ваша программа никогда не вызывала OutOfMemoryException. Поскольку GC может очищать программные ссылки при увеличении размера кучи ... вы можете управлять своим собственным поколением, как через несколько секунд вы можете поместить свои изображения в этот список, и перед загрузкой вы должны убедиться, что если изображение существует, не загружайте его снова, а собирайте это из этого списка, а также положить его обратно в список мягких ссылок, и через некоторое время вы можете очистить свой жесткий список :)
  • 35
    Проект Google Shelves - отличный пример того, как они сделали code.google.com/p/shelves.
Показать ещё 12 комментариев
983

Я сделал простую демонстрацию ленивого списка (расположенного в GitHub) с изображениями. Это может быть полезно кому-то. Он загружает изображения в фоновый поток. Изображения кэшируются на SD-карте и в памяти. Реализация кэша очень проста и достаточно для демонстрации. Я декодирую изображения с помощью inSampleSize для уменьшения потребления памяти. Я также стараюсь правильно обрабатывать переработанные виды.

Изображение 2768

  • 6
    Спасибо, я использую слегка измененную версию вашего кода почти везде в моем проекте: code.google.com/p/vimeoid/source/browse/apk/src/com/fedorvlasov/…
  • 2
    Кто-нибудь смотрел на код Жиля Дебунна в качестве альтернативы. Я вижу две большие разницы: 1) в кэшировании памяти и SD-карте и 2) использование AsyncTasks вместо пула потоков. android-developers.blogspot.com/2010/07/...
Показать ещё 21 комментарий
556

Я рекомендую инструмент с открытым исходным кодом Универсальный загрузчик изображений. Первоначально он основан на проекте Федора Власова LazyList и с тех пор значительно улучшился.

  • Загрузка многопоточного изображения
  • Возможность широкой настройки конфигурации ImageLoader (исполнители потоков, downlaoder, декодер, кеш памяти и диска, параметры отображения изображения и т.д.).
  • Возможность кэширования изображений в памяти и/или на sysytem файла устройства (или SD-карты)
  • Возможность "прослушивания" процесса загрузки.
  • Возможность настройки каждого вызова изображения с отдельными параметрами
  • Поддержка виджета
  • Поддержка Android 2.0 +.

Изображение 2769

  • 15
    если вы ищете отличный код «загрузки изображений», который его создатель рассматривает и поддерживает как своего драгоценного ребенка (а не единовременное решение), вы просто нашли его; большие взлеты ностра
  • 0
    Действительно отличная работа, но она немного отстает от моего списка. Если бы вы могли сказать лучшую сборку 'ImageLoader' с лучшей производительностью ... или, может быть, это из-за 'DisplayImageOptions'.
Показать ещё 12 комментариев
154

Многопоточность для производительности, учебник Гилла Дебунна.

Это из блога разработчиков Android. В предлагаемом коде используется:

  • AsyncTasks.
  • Жесткий, ограниченный размер, FIFO cache.
  • Мягкий, легко garbage collect -ed кеш.
  • Заполнитель Drawable во время загрузки.

Изображение 2770

  • 2
    Но он построен на Android 2.2 (Froyo) ...
  • 9
    Он прекрасно работает и в 2.1. Только не используйте AndroidHttpClient.
Показать ещё 4 комментария
102

Обновление: обратите внимание, что этот ответ сейчас довольно неэффективен. Сборщик мусора агрессивно действует на SoftReference и WeakReference, поэтому этот код НЕ подходит для новых приложений. (Вместо этого попробуйте библиотеки, такие как Универсальный загрузчик изображений в других ответах.)

Спасибо Джеймсу за код и Бао-Лонг за предложение использовать SoftReference. Я внедрил изменения SoftReference в код Джеймса. К сожалению, SoftReferences заставил мои изображения слишком быстро собирать мусор. В моем случае это было прекрасно без материала SoftReference, потому что мой размер списка ограничен, а мои изображения малы.

Обсуждалось год назад относительно SoftReferences для групп google: ссылка на поток. В качестве решения слишком ранней сборки мусора они предлагают возможность вручную установить размер кучи VM с помощью dalvik.system.VMRuntime.setMinimumHeapSize(), что для меня не очень привлекательно.

public DrawableManager() {
    drawableMap = new HashMap<String, SoftReference<Drawable>>();
}

public Drawable fetchDrawable(String urlString) {
    SoftReference<Drawable> drawableRef = drawableMap.get(urlString);
    if (drawableRef != null) {
        Drawable drawable = drawableRef.get();
        if (drawable != null)
            return drawable;
        // Reference has expired so remove the key from drawableMap
        drawableMap.remove(urlString);
    }

    if (Constants.LOGGING) Log.d(this.getClass().getSimpleName(), "image url:" + urlString);
    try {
        InputStream is = fetch(urlString);
        Drawable drawable = Drawable.createFromStream(is, "src");
        drawableRef = new SoftReference<Drawable>(drawable);
        drawableMap.put(urlString, drawableRef);
        if (Constants.LOGGING) Log.d(this.getClass().getSimpleName(), "got a thumbnail drawable: " + drawable.getBounds() + ", "
                + drawable.getIntrinsicHeight() + "," + drawable.getIntrinsicWidth() + ", "
                + drawable.getMinimumHeight() + "," + drawable.getMinimumWidth());
        return drawableRef.get();
    } catch (MalformedURLException e) {
        if (Constants.LOGGING) Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
        return null;
    } catch (IOException e) {
        if (Constants.LOGGING) Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
        return null;
    }
}

public void fetchDrawableOnThread(final String urlString, final ImageView imageView) {
    SoftReference<Drawable> drawableRef = drawableMap.get(urlString);
    if (drawableRef != null) {
        Drawable drawable = drawableRef.get();
        if (drawable != null) {
            imageView.setImageDrawable(drawableRef.get());
            return;
        }
        // Reference has expired so remove the key from drawableMap
        drawableMap.remove(urlString);
    }

    final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message message) {
            imageView.setImageDrawable((Drawable) message.obj);
        }
    };

    Thread thread = new Thread() {
        @Override
        public void run() {
            //TODO : set imageView to a "pending" image
            Drawable drawable = fetchDrawable(urlString);
            Message message = handler.obtainMessage(1, drawable);
            handler.sendMessage(message);
        }
    };
    thread.start();
}
  • 2
    Вы можете создавать поколения, такие как жесткое поколение и мягкое поколение. вы можете исправить время очистки кеша очистит все изображения, к которым не было доступа в течение 3 секунд .. вы можете взглянуть на проект Google полки
  • 0
    developer.android.com/reference/java/lang/ref/… Документ SoftReference содержит примечание о кэшировании, см. раздел «Избегайте мягких ссылок для кэширования». Большинство приложений должны использовать android.util.LruCache вместо мягких ссылок.
Показать ещё 2 комментария
80

Пикассо

Используйте библиотеку Пикассо Джейка Уортона. (A Perfect ImageLoading Library формирует разработчика ActionBarSherlock)

Мощная библиотека загрузки и кэширования изображений для Android.

Изображения добавляют столь необходимый контекст и визуальное чутье для приложений Android. Picasso позволяет без проблем загружать изображения в ваше приложение - часто в одной строке кода!

Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);

Многие распространенные ошибки загрузки изображений на Android автоматически обрабатываются Picasso:

Обработка утилиты ImageView и отмена загрузки в адаптере. Комплексные преобразования изображений с минимальным использованием памяти. Автоматическое кэширование памяти и диска.

Библиотека Пикассо Джейка Уортона

Glide

Glide - это быстрая и эффективная среда для управления медиаформатами с открытым исходным кодом для Android, которая включает декодирование мультимедиа, кеширование памяти и дисков, а также объединение ресурсов в простой и удобный интерфейс.

Glide поддерживает выборку, декодирование и отображение видеопотоков, изображений и анимированных GIF файлов. Glide включает гибкий api, который позволяет разработчикам подключаться практически к любому сетевому стеклу. По умолчанию Glide использует собственный стек, основанный на HttpUrlConnection, но также включает в себя утилиты, подключаемые к проекту Google Volley или Square OkHttp.

Glide.with(this).load("http://goo.gl/h8qOq7").into(imageView);

Первым фокусом Glide является прокрутка любого вида списка изображений как можно более плавным и быстрым, но Glide также эффективна практически для любого случая, когда вам нужно выбирать, изменять размер и отображать удаленное изображение.

Библиотека загрузки изображений Glide

Фреско от Facebook

Fresco - это мощная система для отображения изображений в приложениях Android.

Fresco заботится о загрузке и отображении изображений, поэтому вам не нужно. Он загрузит изображения из сети, локального хранилища или локальных ресурсов и покажет местозаполнитель до появления изображения. Он имеет два уровня кеша; один в памяти и другой во внутреннем хранилище.

Fresco Github

В Android 4.x и ниже Fresco помещает изображения в специальную область памяти Android. Это позволяет вашему приложению работать быстрее - и страдать от ужасного OutOfMemoryError гораздо реже.

Документация Fresco

  • 0
    Picasso - это библиотека, разработанная Square
78

Я следил за этим обучением Android, и я думаю, что он отлично справляется с загрузкой изображений без блокировки основного пользовательского интерфейса. Он также обрабатывает кеширование и имеет дело с прокруткой многих изображений: Эффективная загрузка больших растровых изображений

Изображение 2771

  • 0
    Извините, я указал только на один класс для приложения Google IO (и я слишком поздно для редактирования). Вы должны действительно изучить все их служебные классы загрузки и кэширования изображений, которые вы можете найти в том же пакете, что и класс кэширования .
  • 0
    Кто-нибудь порекомендует взять файлы DiskLruCache, Image * .java из папки util приложения iosched, чтобы помочь с обработкой загрузки / кэширования изображений для просмотра списка? Я имею в виду, что определенно стоит следовать интерактивным руководствам для разработчиков по этому вопросу, но эти классы (от iosched) идут немного дальше по шаблону.
77

Высокопроизводительный загрузчик - после изучения предложенных здесь методов, Я использовал решение Ben с некоторыми изменениями -

  • Я понял, что работа с чертежами быстрее, чем с растровыми изображениями, поэтому вместо этого я использую drawables

  • Использование SoftReference замечательно, но он слишком часто удаляет кешированное изображение, поэтому я добавил связанный список, содержащий ссылки на изображения, предотвращающие удаление изображения, до тех пор, пока он не достигнет предопределенного размера

  • Чтобы открыть InputStream, я использовал java.net.URLConnection, который позволяет мне использовать веб-кеш (вам нужно сначала установить кеш ответа, но это другая история)

Мой код:

import java.util.Map; 
import java.util.HashMap; 
import java.util.LinkedList; 
import java.util.Collections; 
import java.util.WeakHashMap; 
import java.lang.ref.SoftReference; 
import java.util.concurrent.Executors; 
import java.util.concurrent.ExecutorService; 
import android.graphics.drawable.Drawable;
import android.widget.ImageView;
import android.os.Handler;
import android.os.Message;
import java.io.InputStream;
import java.net.MalformedURLException; 
import java.io.IOException; 
import java.net.URL;
import java.net.URLConnection;

public class DrawableBackgroundDownloader {    

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 = 80; 
public int THREAD_POOL_SIZE = 3;

/**
 * Constructor
 */
public DrawableBackgroundDownloader() {  
    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.setImageDrawable(drawable);  
    } else {  
        imageView.setImageDrawable(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.setImageDrawable((Drawable) msg.obj);  
                    } else {  
                        imageView.setImageDrawable(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;
}
}
  • 0
    Работает отлично! Кстати, в названии класса есть опечатка.
  • 4
    В случае, если это сэкономит кому-то время: import java.util.Map; import java.util.HashMap; import java.util.LinkedList; import java.util.Collections; import java.util.WeakHashMap; import java.lang.ref.SoftReference; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import android.graphics.drawable.Drawable; import android.widget.ImageView; import android.os.Handler; import android.os.Message; import java.io.InputStream; import java.net.MalformedURLException; import java.io.IOException; import java.net.URL; import java.net.URLConnection;
Показать ещё 9 комментариев
56

1. Picasso позволяет без проблем загружать изображения в ваше приложение - часто в одной строке кода!

Использовать Gradle:

implementation 'com.squareup.picasso:picasso:2.71828'

Всего одна строка кода!

Picasso.get().load("http://i.imgur.com/DvpvklR.png").into(imageView);

2. Glide. Библиотека загрузки изображений и кеширования для Android ориентирована на плавную прокрутку

Использовать Gradle:

repositories {
  mavenCentral() 
  google()
}

dependencies {
   implementation 'com.github.bumptech.glide:glide:4.7.1'
   annotationProcessor 'com.github.bumptech.glide:compiler:4.7.1'
}

//Для простого представления:

  Glide.with(this).load("http://i.imgur.com/DvpvklR.png").into(imageView);

3. fresco - мощная система для отображения изображений в приложениях Android. Fresco берет на себя загрузку и отображение изображений, поэтому вам не нужно.

Начало работы с Fresco

48

Я написал учебник, в котором объясняется, как делать ленивую загрузку изображений в виде списка. Я подробно расскажу о проблемах утилизации и concurrency. Я также использую фиксированный пул потоков, чтобы предотвратить нерестование большого количества потоков.

Ленивая загрузка изображений в учебнике по просмотру

39

То, как я это делаю, - это запустить поток для загрузки изображений в фоновом режиме и передать ему обратный вызов для каждого элемента списка. Когда изображение закончено, он вызывает обратный вызов, который обновляет представление для элемента списка.

Этот метод работает не очень хорошо, когда вы повторно просматриваете представления.

  • 0
    Я использую нить для каждого изображения. Если вы отделите свою модель от своего представления, вы можете сохранить модель вне Activity (как в вашем классе 'application'), чтобы сохранить их в кэше. Остерегайтесь нехватки ресурсов, если у вас много изображений.
  • 0
    Можете ли вы уточнить, пожалуйста. Я новичок в разработке Android. Спасибо за советы, хотя
Показать ещё 2 комментария
30

Я просто хочу добавить еще один хороший пример, XML-адаптеры. Поскольку он используется Google, и я также использую ту же логику, чтобы избежать ошибки OutOfMemory.

В основном этот ImageDownloader - ваш ответ (поскольку он охватывает большинство ваших требований). Некоторые из них также можно реализовать в этом.

27

Я использую NetworkImageView из новой библиотеки волейбола Android com.android.volley.toolbox.NetworkImageView, и, похоже, он работает очень хорошо. По-видимому, это та же точка зрения, которая используется в Google Play и других новых приложениях Google. Определенно стоит проверить.

  • 1
    Я думаю, что это лучшее решение - другие ответы очень старые - залп действительно быстрый и в сочетании с jake warthons disklrucache - это идеальное решение - я пробовал много других, но ни один не стабилен и быстр как залп
26

Это обычная проблема для Android, которая многими была решена многими способами. На мой взгляд, лучшим решением, которое я видел, является относительно новая библиотека под названием Picasso. Вот основные моменты:

  • Открытый исходный код, но возглавил Jake Wharton ActionBarSherlock.
  • Асинхронная загрузка изображений из сетевых ресурсов или приложений с помощью одной строки кода
  • Автоматическое обнаружение ListView
  • Автоматическое кэширование дисков и памяти
  • Может выполнять пользовательские преобразования
  • Множество настраиваемых параметров
  • Супер простой API
  • Часто обновляемый
23

Я думаю, что эта проблема очень популярна среди разработчиков Android, и есть много таких библиотек, которые претендуют на решение этой проблемы, но только некоторые из них, похоже, находятся на грани. AQuery - одна из таких библиотек, но она лучше, чем большинство из них во всех аспектах, и стоит попробовать.

22

Ну, время загрузки изображений из Интернета имеет множество решений. Вы также можете использовать библиотеку Android-Query. Это даст вам всю необходимую работу. Убедитесь, что вы хотите сделать и прочитайте страницу вики-библиотеки. И разрешите ограничение загрузки изображения.

Это мой код:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View v = convertView;
    if (v == null) {
        LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        v = vi.inflate(R.layout.row, null);
    }

    ImageView imageview = (ImageView) v.findViewById(R.id.icon);
    AQuery aq = new AQuery(convertView);

    String imageUrl = "http://www.vikispot.com/z/images/vikispot/android-w.png";

    aq.id(imageview).progress(this).image(imageUrl, true, true, 0, 0, new BitmapAjaxCallback() {
        @Override
        public void callback(String url, ImageView iv, Bitmap bm, AjaxStatus status) {
            iv.setImageBitmap(bm);
        }
    ));

    return v;
}

Это должно решить вашу ленивую проблему с загрузкой.

  • 0
    Хорошая работа для меня, но нужен файл Jar для включения в ваш проект. Вы можете скачать этот JAR-файл отсюда. AQuery androidAQuery = new AQuery (this); ссылка: code.google.com/archive/p/android-query/downloads
19

Взгляните на Shutterbug, легкий в использовании SDWebImage (симпатичная библиотека на iOS) для Android. Он поддерживает асинхронное кэширование, хранит неудачные URL-адреса, отлично справляется с concurrency и включает полезные подклассы.

Запросы Pull (и отчеты об ошибках) также приветствуются!

17

Вы должны попробовать этот универсальный загрузчик. Я использую это после выполнения многих RnD при ленивой загрузке.

Универсальный загрузчик изображений

Функции

  • Загрузка многопоточного изображения (асинхронная или синхронизация)
  • Широкая настройка конфигурации ImageLoader (исполнители потоков, загрузчик, декодер, память и кеш диска, параметры отображения изображения и т.д.).
  • Многие параметры настройки для каждого вызова отображаемого изображения (заглушки, кеширующий переключатель, опции декодирования, обработка и отображение растровых изображений и т.д.).
  • Кэширование изображений в памяти и/или на диске (файловая система устройства или SD-карта)
  • Прослушивание процесса загрузки (включая процесс загрузки)

Поддержка Android 2.0+

Изображение 2772

16

DroidParts имеет ImageFetcher, который требует нулевой конфигурации для начала.

  • Использует диск и в памяти Кэш менее всего использованного (LRU).
  • Эффективно декодирует изображения.
  • Поддерживает изменение растровых изображений в фоновом потоке.
  • Простой кросс-фейд.
  • Выполняется обратный вызов прогресса загрузки изображения.

Клон DroidPartsGram для примера:

Изображение 2773

  • 0
    Привет, я посмотрел примеры кода, но у меня возникли проблемы с использованием ImageFetcher с ArrayAdapter, не могли бы вы взглянуть на мой вопрос? stackoverflow.com/questions/21089147/… Спасибо =]
15

Просто быстрый совет для тех, кто в нерешительности относительно того, какую библиотеку использовать для ленивых загружаемых изображений:

Существует четыре основных способа.

  • DIY = > Не лучшее решение, но для нескольких изображений, и если вы хотите обойтись без проблем с использованием других библиотек

  • Volley Lazy Загрузка библиотеки = > От парней в android. Это хорошо и все, но плохо документировано и, следовательно, является проблемой для использования.

  • Picasso: простое решение, которое просто работает, вы даже можете указать точный размер изображения, который вы хотите ввести. Он очень прост в использовании, но может быть не очень "совершенным" для приложений, которым приходится иметь дело с огромное количество изображений.

  • UIL: лучший способ ленивых изображений загрузки. Вы можете кэшировать изображения (вам нужно разрешение, конечно), инициализировать загрузчик один раз, а затем выполнить свою работу. Самая зрелая библиотека загрузки асинхронных изображений, которую я когда-либо видел.

15

Novoda также имеет отличную ленивую библиотеку загрузки изображений, и многие приложения, такие как Songkick, Podio, SecretDJ и ImageSearch, используют свою библиотеку.

Их библиотека размещена здесь в Github, и у них есть довольно активный трекер ошибок. Их проект, похоже, тоже очень активен, и при написании этого ответа более 300 + коммитов.

  • 1
    На самом деле Novoda - отличная библиотека, но ... иногда вам не нужна огромная библиотека, а только простой подход к решению. Вот почему LazyList в Github так хорош, если ваши приложения показывают только изображение в listView и не являются основной функцией вашего приложения, просто еще одно занятие, которое я предпочел бы использовать что-то более светлое. В противном случае, если вы знаете, что вам придется часто пользоваться и является частью ядра, попробуйте Novoda.
13

Проверьте мою вилку LazyList. В основном, я улучшаю LazyList, задерживая вызов ImageView и создавая два метода:

  • Когда вам нужно поставить что-то вроде "Загрузка изображения..."
  • Когда вам нужно показать загруженное изображение.

Я также улучшил ImageLoader, реализовав singleton в этом объекте.

10

Все вышеприведенные коды имеют свою ценность, но с моим личным опытом просто попробуйте Picasso.

Picasso представляет собой библиотеку специально для этой цели, на самом деле она будет автоматически управлять кешем и всеми другими сетевыми операциями. Вам нужно будет добавить библиотеку в свой проект и просто написать одну строку кода для загрузки изображения с удаленного URL.

Пожалуйста, посетите здесь: http://code.tutsplus.com/tutorials/android-sdk-working-with-picasso--cms-22149

7

URLImageViewHelper - это потрясающая библиотека, которая поможет вам в этом.

7

Дайте "Аквери" . У этого есть удивительно простые методы для загрузки и кэширования изображений асинхронно.

7

Я могу порекомендовать другой способ, который работает как шарм: Android-запрос.

Вы можете загрузить этот JAR файл из здесь

AQuery androidAQuery = new AQuery(this);

В качестве примера:

androidAQuery.id(YOUR IMAGEVIEW).image(YOUR IMAGE TO LOAD, true, true, getDeviceWidth(), ANY DEFAULT IMAGE YOU WANT TO SHOW);

Это очень быстро и точно, и с помощью этого вы можете найти еще много функций, таких как анимация при загрузке, получение растрового изображения (если необходимо) и т.д.

5

Используйте библиотеку скольжения. Он работал у меня и будет работать и для вашего кода. Он работает как для изображений, так и для gif.

ImageView imageView = (ImageView) findViewById(R.id.test_image); 
    GlideDrawableImageViewTarget imagePreview = new GlideDrawableImageViewTarget(imageView);
    Glide
            .with(this)
            .load(url)
            .listener(new RequestListener<String, GlideDrawable>() {
                @Override
                public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {                       
                    return false;
                }

                @Override
                public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
                    return false;
                }
            })
            .into(imagePreview);
}
4

Вы можете попробовать библиотеку Aquery Android для ленивого загружаемого изображения и списка... Ниже приведен код, который может вам помочь..... скачать библиотеку здесь.

AQuery aq = new AQuery(mContext);
aq.id(R.id.image1).image("http://data.whicdn.com/images/63995806/original.jpg");
4

У меня была эта проблема и реализован lruCache. Я считаю, что вам нужен API 12 и выше или используйте библиотеку совместимости v4. lurCache - это быстрая память, но у нее также есть бюджет, поэтому, если вы беспокоитесь об этом, вы можете использовать diskcache... Все это описано в Кэширование битмапов.

Теперь я предоставил свою реализацию, которая является singleton, которую я вызываю из любого места:

//Where the first is a string and the other is a imageview to load.

DownloadImageTask.getInstance().loadBitmap(avatarURL, iv_avatar);

Здесь идеальный код для кэширования, а затем вызывается выше в getView адаптера при извлечении веб-изображения:

public class DownloadImageTask {

    private LruCache<String, Bitmap> mMemoryCache;

    /* Create a singleton class to call this from multiple classes */

    private static DownloadImageTask instance = null;

    public static DownloadImageTask getInstance() {
        if (instance == null) {
            instance = new DownloadImageTask();
        }
        return instance;
    }

    //Lock the constructor from public instances
    private DownloadImageTask() {

        // Get max available VM memory, exceeding this amount will throw an
        // OutOfMemory exception. Stored in kilobytes as LruCache takes an
        // int in its constructor.
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

        // Use 1/8th of the available memory for this memory cache.
        final int cacheSize = maxMemory / 8;

        mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap bitmap) {
                // The cache size will be measured in kilobytes rather than
                // number of items.
                return bitmap.getByteCount() / 1024;
            }
        };
    }

    public void loadBitmap(String avatarURL, ImageView imageView) {
        final String imageKey = String.valueOf(avatarURL);

        final Bitmap bitmap = getBitmapFromMemCache(imageKey);
        if (bitmap != null) {
            imageView.setImageBitmap(bitmap);
        } else {
            imageView.setImageResource(R.drawable.ic_launcher);

            new DownloadImageTaskViaWeb(imageView).execute(avatarURL);
        }
    }

    private void addBitmapToMemoryCache(String key, Bitmap bitmap) {
        if (getBitmapFromMemCache(key) == null) {
            mMemoryCache.put(key, bitmap);
        }
    }

    private Bitmap getBitmapFromMemCache(String key) {
        return mMemoryCache.get(key);
    }

    /* A background process that opens a http stream and decodes a web image. */

    class DownloadImageTaskViaWeb extends AsyncTask<String, Void, Bitmap> {
        ImageView bmImage;

        public DownloadImageTaskViaWeb(ImageView bmImage) {
            this.bmImage = bmImage;
        }

        protected Bitmap doInBackground(String... urls) {

            String urldisplay = urls[0];
            Bitmap mIcon = null;
            try {
                InputStream in = new java.net.URL(urldisplay).openStream();
                mIcon = BitmapFactory.decodeStream(in);

            } 
            catch (Exception e) {
                Log.e("Error", e.getMessage());
                e.printStackTrace();
            }

            addBitmapToMemoryCache(String.valueOf(urldisplay), mIcon);

            return mIcon;
        }

        /* After decoding we update the view on the main UI. */
        protected void onPostExecute(Bitmap result) {
            bmImage.setImageBitmap(result);
        }
    }
}
4
public class ImageDownloader {

Map<String, Bitmap> imageCache;

public ImageDownloader() {
    imageCache = new HashMap<String, Bitmap>();

}

// download function
public void download(String url, ImageView imageView) {
    if (cancelPotentialDownload(url, imageView)) {

        // Caching code right here
        String filename = String.valueOf(url.hashCode());
        File f = new File(getCacheDirectory(imageView.getContext()),
                filename);

        // Is the bitmap in our memory cache?
        Bitmap bitmap = null;

        bitmap = (Bitmap) imageCache.get(f.getPath());

        if (bitmap == null) {

            bitmap = BitmapFactory.decodeFile(f.getPath());

            if (bitmap != null) {
                imageCache.put(f.getPath(), bitmap);
            }

        }
        // No? download it
        if (bitmap == null) {
            try {
                BitmapDownloaderTask task = new BitmapDownloaderTask(
                        imageView);
                DownloadedDrawable downloadedDrawable = new DownloadedDrawable(
                        task);
                imageView.setImageDrawable(downloadedDrawable);
                task.execute(url);
            } catch (Exception e) {
                Log.e("Error==>", e.toString());
            }

        } else {
            // Yes? set the image
            imageView.setImageBitmap(bitmap);
        }
    }
}

// cancel a download (internal only)
private static boolean cancelPotentialDownload(String url,
        ImageView imageView) {
    BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);

    if (bitmapDownloaderTask != null) {
        String bitmapUrl = bitmapDownloaderTask.url;
        if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) {
            bitmapDownloaderTask.cancel(true);
        } else {
            // The same URL is already being downloaded.
            return false;
        }
    }
    return true;
}

// gets an existing download if one exists for the imageview
private static BitmapDownloaderTask getBitmapDownloaderTask(
        ImageView imageView) {
    if (imageView != null) {
        Drawable drawable = imageView.getDrawable();
        if (drawable instanceof DownloadedDrawable) {
            DownloadedDrawable downloadedDrawable = (DownloadedDrawable) drawable;
            return downloadedDrawable.getBitmapDownloaderTask();
        }
    }
    return null;
}

// our caching functions
// Find the dir to save cached images
private static File getCacheDirectory(Context context) {
    String sdState = android.os.Environment.getExternalStorageState();
    File cacheDir;

    if (sdState.equals(android.os.Environment.MEDIA_MOUNTED)) {
        File sdDir = android.os.Environment.getExternalStorageDirectory();

        // TODO : Change your diretcory here
        cacheDir = new File(sdDir, "data/ToDo/images");
    } else
        cacheDir = context.getCacheDir();

    if (!cacheDir.exists())
        cacheDir.mkdirs();
    return cacheDir;
}

private void writeFile(Bitmap bmp, File f) {
    FileOutputStream out = null;

    try {
        out = new FileOutputStream(f);
        bmp.compress(Bitmap.CompressFormat.PNG, 80, out);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (out != null)
                out.close();
        } catch (Exception ex) {
        }
    }
}

// download asynctask
public class BitmapDownloaderTask extends AsyncTask<String, Void, Bitmap> {
    private String url;
    private final WeakReference<ImageView> imageViewReference;

    public BitmapDownloaderTask(ImageView imageView) {
        imageViewReference = new WeakReference<ImageView>(imageView);
    }

    @Override
    // Actual download method, run in the task thread
    protected Bitmap doInBackground(String... params) {
        // params comes from the execute() call: params[0] is the url.
        url = (String) params[0];
        return downloadBitmap(params[0]);
    }

    @Override
    // Once the image is downloaded, associates it to the imageView
    protected void onPostExecute(Bitmap bitmap) {
        if (isCancelled()) {
            bitmap = null;
        }

        if (imageViewReference != null) {
            ImageView imageView = imageViewReference.get();
            BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);
            // Change bitmap only if this process is still associated with
            // it
            if (this == bitmapDownloaderTask) {
                imageView.setImageBitmap(bitmap);

                // cache the image

                String filename = String.valueOf(url.hashCode());
                File f = new File(
                        getCacheDirectory(imageView.getContext()), filename);

                imageCache.put(f.getPath(), bitmap);

                writeFile(bitmap, f);
            }
        }
    }

}

static class DownloadedDrawable extends ColorDrawable {
    private final WeakReference<BitmapDownloaderTask> bitmapDownloaderTaskReference;

    public DownloadedDrawable(BitmapDownloaderTask bitmapDownloaderTask) {
        super(Color.WHITE);
        bitmapDownloaderTaskReference = new WeakReference<BitmapDownloaderTask>(
                bitmapDownloaderTask);
    }

    public BitmapDownloaderTask getBitmapDownloaderTask() {
        return bitmapDownloaderTaskReference.get();
    }
}

// the actual download code
static Bitmap downloadBitmap(String url) {
    HttpParams params = new BasicHttpParams();
    params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION,
            HttpVersion.HTTP_1_1);
    HttpClient client = new DefaultHttpClient(params);
    final HttpGet getRequest = new HttpGet(url);

    try {
        HttpResponse response = client.execute(getRequest);
        final int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode != HttpStatus.SC_OK) {
            Log.w("ImageDownloader", "Error " + statusCode
                    + " while retrieving bitmap from " + url);
            return null;
        }

        final HttpEntity entity = response.getEntity();
        if (entity != null) {
            InputStream inputStream = null;
            try {
                inputStream = entity.getContent();
                final Bitmap bitmap = BitmapFactory
                        .decodeStream(inputStream);
                return bitmap;
            } finally {
                if (inputStream != null) {
                    inputStream.close();
                }
                entity.consumeContent();
            }
        }
    } catch (Exception e) {
        // Could provide a more explicit error message for IOException or
        // IllegalStateException
        getRequest.abort();
        Log.w("ImageDownloader", "Error while retrieving bitmap from "
                + url + e.toString());
    } finally {
        if (client != null) {
            // client.close();
        }
    }
    return null;
 }
}
3

Некоторые ответы уже упоминались с использованием различных библиотек изображений, таких как Universal Image Loader и androidimageloader и т.д. Это старый вопрос, но для тех, кто все еще ищет что-то вроде этого, есть несколько таких библиотек для загрузки/кэширования изображений.

3

Я использую droidQuery. Существует два механизма загрузки изображения из URL-адреса. Первая (стенография) проста:

$.with(myView).image(url);

Это можно легко добавить в метод ArrayAdapter getView(...).


Метод longhand даст намного больший контроль и содержит параметры, которые даже не обсуждаются здесь (например, кэширование и обратные вызовы), но базовую реализацию, которая задает размер вывода 200px x 200px, можно найти здесь:

$.ajax(new AjaxOptions().url(url)
    .type("GET")
    .dataType("image")
    .imageWidth(200).imageHeight(200)
    .success(new Function() {
        @Override
        public void invoke($ droidQuery, Object... params) {
            myImageView.setImageBitmap((Bitmap) params[0]);
        }
    })
    .error(new Function() {
        @Override
        public void invoke($ droidQuery, Object... params) {
            AjaxError e = (AjaxError) params[0];
            Log.e("$", "Error " + e.status + ": " + e.error);
        }
    })
);
2

Если вы хотите отобразить макет Shimmer, например Facebook, для этого есть официальная библиотека facebok. FaceBook Shimmer Android

Он заботится обо всем, вам просто нужно ввести желаемый код проекта в гнездовую рамку. Вот пример кода.

<Предварительно > <код > < com.facebook.shimmer.ShimmerFrameLayout    андроид: идентификатор = "@+ идентификатор /shimmer _view_container"    андроид: layout_width = "wrap_content"    андроид: layout_height = "wrap_content"    мерцающий: длительность = "1000" >  < здесь будет ваш контент для отображения / > & Л; /com.facebook.shimmer.ShimmerFrameLayout > Код >

И вот для него код Java.

  ShimmerFrameLayout shimmerContainer = (ShimmerFrameLayout) findViewById (R.id.shimmer_view_container);
shimmerContainer.startShimmerAnimation();
Код>

Добавьте эту зависимость в файл gradle.

  реализация 'com.facebook.shimmer: shimmer: 0.1.0@aar'
Код>

Вот как это выглядит. Изображение 2774

2

Другой способ сделать это через ваш адаптер в потоке в методе getView():

Thread pics_thread = new Thread(new Runnable() {
    @Override
    public void run() {
        Bitmap bitmap = getPicture(url);
        if(bitmap != null) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    holder.imageview.setImageBitmap(bitmap);            
                    adapter.notifyDataSetChanged();
                }                       
            });             
        }       
    }                       
});

pics_thread.start();

конечно, вы всегда должны кэшировать свои изображения, чтобы избежать дополнительных операций, вы можете поместить свои изображения в массив HashMap, проверить, существует ли изображение в массиве, если нет, продолжить поток или загрузить изображение из вас Массив HashMap. Также всегда проверяйте, что вы не пропускаете память, растровые изображения и чертежи часто бывают тяжелыми в памяти. Вы можете оптимизировать свой код.

  • 0
    Конечно, мне нравится получать растровые изображения в другом потоке. Но единственная проблема, с которой я столкнулся, имея этот код в getView (), это то, что для нескольких изображений будет запущено много потоков. И getView может попытаться загрузить много или несколько изображений одновременно.
1

Для эффективной ленивой загрузки вы можете использовать стороннюю библиотеку, такую ​​как Piccaso или Volley. Вы также можете создать свой собственный, выполнив ниже

  • Внедрить код для загрузки изображения из URL

  • Реализовать механизм кэширования для хранения и получения изображения (используйте LruCache для android для кеширования)

1

используйте ниже класс для загрузки и загрузки изображений в listview. Он кэширует все изображения после загрузки. Также загружает изображения с ленивой загрузкой.

package com.fudiyoxpress.images;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.widget.ImageView;

import com.fudiyoxpress.R;
import com.fudiyoxpress.config.Config;
import com.fudiyoxpress.twitter.ScaleBitmap;

public class ImageLoader {

    // Initialize MemoryCache
    MemoryCache memoryCache = new MemoryCache();

    FileCache fileCache;

    Context C;

    // Create Map (collection) to store image and image url in key value pair
    private Map<ImageView, String> imageViews = Collections
            .synchronizedMap(new WeakHashMap<ImageView, String>());
    ExecutorService executorService;

    // handler to display images in UI thread
    Handler handler = new Handler();

    public ImageLoader(Context context) {

        C = context;
        fileCache = new FileCache(context);

        // Creates a thread pool that reuses a fixed number of
        // threads operating off a shared unbounded queue.
        executorService = Executors.newFixedThreadPool(5);

    }

    // default image show in list (Before online image download)
    final int stub_id = R.drawable.restlogoplaceholder;

    public void DisplayImage(String url, ImageView imageView, Context context,
            boolean header_flag) {

        Bitmap largeIcon = BitmapFactory.decodeResource(context.getResources(),
                R.drawable.restlogoplaceholder);
        header_flag = false;
        // Store image and url in Map
        imageViews.put(imageView, url);

        // Check image is stored in MemoryCache Map or not (see
        // MemoryCache.java)
        Bitmap bitmap = memoryCache.get(url);

        if (bitmap != null) {
            // if image is stored in MemoryCache Map then
            // Show image in listview row
            Bitmap b = ScaleBitmap
                    .getScaledBitmap(context, bitmap, header_flag);
            imageView.setImageBitmap(b);

        } else {
            // queue Photo to download from url
            queuePhoto(url, imageView, header_flag);

            // Before downloading image show default image
            imageView.setImageBitmap(ScaleBitmap.getScaledBitmap(context,
                    largeIcon, header_flag));

        }
    }



    private void queuePhoto(String url, ImageView imageView, boolean header_flag) {
        // Store image and url in PhotoToLoad object
        PhotoToLoad p = new PhotoToLoad(url, imageView, header_flag);

        // pass PhotoToLoad object to PhotosLoader runnable class
        // and submit PhotosLoader runnable to executers to run runnable
        // Submits a PhotosLoader runnable task for execution

        executorService.submit(new PhotosLoader(p));
    }

    // Task for the queue
    private class PhotoToLoad {
        public String url;
        public ImageView imageView;
        public boolean b;

        public PhotoToLoad(String u, ImageView i, boolean header_flag) {
            url = u;
            imageView = i;
            b = header_flag;
        }
    }

    class PhotosLoader implements Runnable {
        PhotoToLoad photoToLoad;

        PhotosLoader(PhotoToLoad photoToLoad) {
            this.photoToLoad = photoToLoad;
        }

        @Override
        public void run() {
            try {
                // Check if image already downloaded
                if (imageViewReused(photoToLoad))
                    return;
                // download image from web url
                Bitmap bmp = getBitmap(photoToLoad.url);

                // set image data in Memory Cache
                memoryCache.put(photoToLoad.url, bmp);

                if (imageViewReused(photoToLoad))
                    return;

                // Get bitmap to display
                BitmapDisplayer bd = new BitmapDisplayer(bmp, photoToLoad);

                // Causes the Runnable bd (BitmapDisplayer) to be added to the
                // message queue.
                // The runnable will be run on the thread to which this handler
                // is attached.
                // BitmapDisplayer run method will call
                handler.post(bd);

            } catch (Throwable th) {
                // th.printStackTrace();
            }
        }
    }

    private Bitmap getBitmap(String url) {
        File f = fileCache.getFile(url);

        // from SD cache
        // CHECK : if trying to decode file which not exist in cache return null
        Bitmap b = decodeFile(f);
        if (b != null)
            return b;

        // Download image file from web
        try {

            // // download the image
            Bitmap bitmap = null;

            URL imageURL = null;
            try {

                imageURL = new URL(Config.WEB_URL + "/ServeBlob?id=" + url);

                HttpURLConnection connection = (HttpURLConnection) imageURL
                        .openConnection();
                connection.setDoInput(true);
                connection.connect();
                // if(!(new File(imageURL.toString())).exists())
                // {
                // imageURL=new URL("");
                // }
                InputStream inputStream = connection.getInputStream();

                // Constructs a new FileOutputStream that writes to
                // file
                // if file not exist then it will create file
                OutputStream os = new FileOutputStream(f);

                // See Utils class CopyStream method
                // It will each pixel from input stream and
                // write pixels to output stream (file)
                Utils.CopyStream(inputStream, os);

                os.close();

                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inSampleSize = 8;

                bitmap = BitmapFactory.decodeStream(inputStream, null, options);

            } catch (IOException e) {

                // e.printStackTrace();
            }

            // Now file created and going to resize file with defined height
            // Decodes image and scales it to reduce memory consumption
            bitmap = decodeFile(f);

            return bitmap;

        } catch (Throwable ex) {
            ex.printStackTrace();
            if (ex instanceof OutOfMemoryError)
                memoryCache.clear();
            return null;
        }
    }

    // Decodes image and scales it to reduce memory consumption
    private Bitmap decodeFile(File f) {

        try {

            // Decode image size
            BitmapFactory.Options o = new BitmapFactory.Options();
            o.inJustDecodeBounds = true;
            FileInputStream stream1 = new FileInputStream(f);
            BitmapFactory.decodeStream(stream1, null, o);
            stream1.close();

            // Find the correct scale value. It should be the power of 2.

            // Set width/height of recreated image
            final int REQUIRED_SIZE = 85;

            int width_tmp = o.outWidth, height_tmp = o.outHeight;
            int scale = 1;
            while (true) {
                if (width_tmp / 2 < REQUIRED_SIZE
                        || height_tmp / 2 < REQUIRED_SIZE)
                    break;
                width_tmp /= 2;
                height_tmp /= 2;
                scale *= 2;
            }

            // decode with current scale values
            BitmapFactory.Options o2 = new BitmapFactory.Options();
            o2.inSampleSize = scale;
            FileInputStream stream2 = new FileInputStream(f);
            Bitmap bitmap = BitmapFactory.decodeStream(stream2, null, o2);
            stream2.close();
            return bitmap;

        } catch (FileNotFoundException e) {
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    boolean imageViewReused(PhotoToLoad photoToLoad) {

        String tag = imageViews.get(photoToLoad.imageView);
        // Check url is already exist in imageViews MAP
        if (tag == null || !tag.equals(photoToLoad.url))
            return true;
        return false;
    }

    // Used to display bitmap in the UI thread
    class BitmapDisplayer implements Runnable {
        Bitmap bitmap;
        PhotoToLoad photoToLoad;

        public BitmapDisplayer(Bitmap b, PhotoToLoad p) {
            bitmap = b;
            photoToLoad = p;
        }

        public void run() {
            if (imageViewReused(photoToLoad))
                return;

            // Show bitmap on UI
            if (bitmap != null) {
                photoToLoad.imageView.setImageBitmap(ScaleBitmap
                        .getScaledBitmap(C, bitmap, photoToLoad.b));
            } else {

            }
            // photoToLoad.imageView.setImageResource(stub_id);

        }
    }

    public void clearCache() {
        // Clear cache directory downloaded images and stored data in maps
        memoryCache.clear();
        fileCache.clear();
    }

}




package com.fudiyoxpress.images;

import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import android.graphics.Bitmap;
import android.util.Log;

public class MemoryCache {

    private static final String TAG = "MemoryCache";

    //Last argument true for LRU ordering
    private Map<String, Bitmap> cache = Collections.synchronizedMap(
            new LinkedHashMap<String, Bitmap>(10,1.5f,true));

   //current allocated size
    private long size=0; 

    //max memory cache folder used to download images in bytes
    private long limit = 1000000; 

    public MemoryCache(){

        //use 25% of available heap size
        setLimit(Runtime.getRuntime().maxMemory()/4);
    }

    public void setLimit(long new_limit){

        limit=new_limit;
        Log.i(TAG, "MemoryCache will use up to "+limit/1024./1024.+"MB");
    }

    public Bitmap get(String id){
        try{
            if(!cache.containsKey(id))
                return null;
            //NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78 
            return cache.get(id);
        }catch(NullPointerException ex){
            ex.printStackTrace();
            return null;
        }
    }

    public void put(String id, Bitmap bitmap){
        try{
            if(cache.containsKey(id))
                size-=getSizeInBytes(cache.get(id));
            cache.put(id, bitmap);
            size+=getSizeInBytes(bitmap);
            checkSize();
        }catch(Throwable th){
            th.printStackTrace();
        }
    }

    private void checkSize() {
        Log.i(TAG, "cache size="+size+" length="+cache.size());
        if(size>limit){
            Iterator<Entry<String, Bitmap>> iter=cache.entrySet().iterator();//least recently accessed item will be the first one iterated  
            while(iter.hasNext()){
                Entry<String, Bitmap> entry=iter.next();
                size-=getSizeInBytes(entry.getValue());
                iter.remove();
                if(size<=limit)
                    break;
            }
            Log.i(TAG, "Clean cache. New size "+cache.size());
        }
    }

    public void clear() {
        try{
            //NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78 
            cache.clear();
            size=0;
        }catch(NullPointerException ex){
            ex.printStackTrace();
        }
    }

    long getSizeInBytes(Bitmap bitmap) {
        if(bitmap==null)
            return 0;
        return bitmap.getRowBytes() * bitmap.getHeight();
    }
}




package com.fudiyoxpress.images;

import java.io.InputStream;
import java.io.OutputStream;

public class Utils {
    public static void CopyStream(InputStream is, OutputStream os)
    {
        final int buffer_size=1024;
        try
        {

            byte[] bytes=new byte[buffer_size];
            for(;;)
            {
              //Read byte from input stream

              int count=is.read(bytes, 0, buffer_size);
              if(count==-1)
                  break;

              //Write byte from output stream
              os.write(bytes, 0, count);
            }
        }
        catch(Exception ex){}
    }
}
1

Я нашел Glide лучшим вариантом, чем Picasso. Я использовал picasso для загрузки вокруг 32 изображений размером около 200-500KB каждый, и я всегда получал OOM. Но Glide решил все мои проблемы OOM.

  • 0
    Конечно, Picasso хранит полный размер изображения для кэша, в то время как Glide хранит только оптимизированные изображения.
-2

За исключением загрузки кеша данных асинхронно, для кэша пользовательского интерфейса может потребоваться

Кроме данных загрузки видимых элементов, вам может потребоваться загрузить данные о приближении видимых элементов

Пример: Предположим, что видимым элементом списка является [6,7,8,9,10], вам может потребоваться загрузить [6,7,8,9,10] и предварительно загрузить элемент [1, 2, 3, 4, 5 ] и [11, 12, 13, 14, 15], потому что пользователь, вероятно, прокручивает страницу до страницы или страницы

  • 1
    В дополнение к вашему описанию, пожалуйста, включите некоторый код для дальнейшего улучшения вашего ответа.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню