Вопрос:

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

android image listview url universal-image-loader

535395 просмотра

30 ответа

40055 Репутация автора

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

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

Автор: lostInTransit Источник Размещён: 12.02.2009 03:59

Ответы (30)


40 плюса

2433 Репутация автора

The way I do it is by launching a thread to download the images in the background and hand it a callback for each list item. When an image is finished downloading it calls the callback which updates the view for the list item.

This method doesn't work very well when you're recycling views however.

Автор: jasonhudgins Размещён: 12.02.2009 08:07

1067 плюса

13080 Репутация автора

Решение

Вот то, что я создал для хранения изображений, которые мое приложение отображает в данный момент. Обратите внимание, что используемый здесь объект «Log» - это моя специальная оболочка для заключительного класса Log внутри 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();
    }
}
Автор: James A Wilson Размещён: 18.02.2009 03:56

106 плюса

7593 Репутация автора

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

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

Существует год назад обсуждение SoftReferences в группах Google: ссылка на тему . В качестве решения для слишком ранней сборки мусора, они предлагают возможность вручную установить размер кучи виртуальной машины с помощью 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();
}
Автор: TalkLittle Размещён: 05.05.2010 01:16

1017 плюса

41061 Репутация автора

Я сделал простую демонстрацию ленивого списка (расположенного на GitHub) с изображениями.

Основное использование

ImageLoader imageLoader=new ImageLoader(context); ...
imageLoader.DisplayImage(url, imageView); 

Не забудьте добавить следующие разрешения в ваш AndroidManifest.xml:

 <uses-permission android:name="android.permission.INTERNET"/>
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> Please

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

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

Альтернативный текст

Автор: Fedor Размещён: 18.06.2010 08:04

155 плюса

22786 Репутация автора

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

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

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

введите описание изображения здесь

Автор: Thomas Ahle Размещён: 12.08.2010 11:07

51 плюса

3167 Репутация автора

I've written a tutorial that explains how to do lazy-loading of images in a listview. I go into some detail about the issues of recycling and concurrency. I also use a fixed thread pool to prevent spawning a lot of threads.

Lazy loading of images in Listview Tutorial

Автор: Ben Ruijl Размещён: 27.08.2011 12:54

81 плюса

11249 Репутация автора

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

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

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

  3. Чтобы открыть 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;
}
}
Автор: Asaf Pinhassi Размещён: 22.10.2011 04:44

31 плюса

16276 Репутация автора

I just want to add one more good example, XML Adapters. As it's is used by Google and I am also using the same logic to avoid an OutOfMemory error.

Basically this ImageDownloader is your answer (as it covers most of your requirements). Some you can also implement in that.

Автор: Arslan Anwar Размещён: 14.12.2011 10:57

548 плюса

12176 Репутация автора

Я рекомендую инструмент с открытым исходным кодом Universal Image Loader . Первоначально он основан на проекте Федора Власова LazyList и с тех пор значительно улучшился.

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

Автор: nostra13 Размещён: 19.12.2011 01:53

20 плюса

2612 Репутация автора

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

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

Автор: PatrickNLT Размещён: 16.10.2012 12:43

24 плюса

496 Репутация автора

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

Автор: Ritesh Kumar Dubey Размещён: 11.12.2012 06:33

77 плюса

4438 Репутация автора

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

Автор: toobsco42 Размещён: 27.12.2012 11:27

15 плюса

4379 Репутация автора

Novoda also has a great lazy image loading library and many apps like Songkick, Podio, SecretDJ and ImageSearch use their library.

Their library is hosted here on Github and they have a pretty active issues tracker as well. Their project seems to be pretty active too, with over 300+ commits at the time of writing this reply.

Автор: Soham Размещён: 12.01.2013 11:00

25 плюса

539 Репутация автора

Ну, время загрузки изображения из Интернета имеет много решений. Вы также можете использовать библиотеку 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;
}

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

Автор: Rahul Rawat Размещён: 12.02.2013 07:10

13 плюса

1292 Репутация автора

Check my fork of LazyList. Basically, I improve the LazyList by delaying the call of the ImageView and create two methods:

  1. When you need to put something like "Loading image..."
  2. When you need to show the downloaded image.

I also improved the ImageLoader by implementing a singleton in this object.

Автор: Nicolas Jafelle Размещён: 12.02.2013 11:46

16 плюса

43819 Репутация автора

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

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

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

Введите описание изображения здесь

Автор: yanchenko Размещён: 06.05.2013 09:48

28 плюса

505 Репутация автора

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

Автор: droidment Размещён: 13.06.2013 03:17

4 плюса

51 Репутация автора

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;
 }
}
Автор: Nikhil Gupta Размещён: 18.07.2013 07:16

4 плюса

29031 Репутация автора

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

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

//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);
        }
    }
}
Автор: j2emanue Размещён: 21.07.2013 05:51

7 плюса

6147 Репутация автора

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

Вы можете скачать этот файл 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);

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

Автор: Pratik Dasa Размещён: 29.07.2013 07:06

28 плюса

7829 Репутация автора

This is a common problem on Android that has been solved in many ways by many people. In my opinion the best solution I've seen is the relatively new library called Picasso. Here are the highlights:

  • Open source, but headed up by Jake Wharton of ActionBarSherlock fame.
  • Asynchronously load images from network or app resources with one line of code
  • Automatic ListView detection
  • Automatic disk and memory caching
  • Can do custom transformations
  • Lots of configurable options
  • Super simple API
  • Frequently updated
Автор: howettl Размещён: 15.10.2013 11:22

7 плюса

687 Репутация автора

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

Автор: user2779311 Размещён: 16.12.2013 01:04

7 плюса

91 Репутация автора

URLImageViewHelper - это удивительная библиотека, которая поможет вам сделать это.

Автор: DiegoAlt Размещён: 27.01.2014 05:33

94 плюса

2728 Репутация автора

Пикассо

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

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

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

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

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

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

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

скольжение

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

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

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

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

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

Фреска от Facebook

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

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

Фреска Гитхуб

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

Фреска Документация

Автор: Ashwin S Ashok Размещён: 04.04.2014 12:35

63 плюса

2821 Репутация автора

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

Используйте Gradle:

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

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

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

2. Glide An image loading and caching library for Android focused on smooth scrolling

Use Gradle:

repositories {
  mavenCentral() 
  google()
}

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

// For a simple view:

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

3. fresco is a powerful system for displaying images in Android applications.Fresco takes care of image loading and display, so you don't have to.

Getting Started with Fresco

Автор: chiragkyada Размещён: 22.05.2014 06:00

16 плюса

460 Репутация автора

Just a quick tip for someone who is in indecision regarding what library to use for lazy-loading images:

There are four basic ways.

  1. DIY => Not the best solution but for a few images and if you want to go without the hassle of using others libraries

  2. Volley's Lazy Loading library => From guys at android. It is nice and everything but is poorly documented and hence is a problem to use.

  3. Picasso: A simple solution that just works, you can even specify the exact image size you want to bring in. It is very simple to use but might not be very "performant" for apps that has to deal with humongous amounts of images.

  4. UIL: The best way to lazy load images. You can cache images(you need permission of course), initialize the loader once, then have your work done. The most mature asynchronous image loading library I have ever seen so far.

Автор: Bijay Koirala Размещён: 03.08.2014 12:19

21 плюса

762 Репутация автора

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

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

Особенности

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

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

введите описание изображения здесь

Автор: Girish Patel Размещён: 05.02.2015 12:45

11 плюса

478 Репутация автора

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

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

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

Автор: AKber Размещён: 09.07.2015 04:16

9 плюса

356 Репутация автора

Используйте библиотеку скольжения. Это сработало для меня и будет работать для вашего кода. Это работает как для изображений, так и для 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);
}
Автор: Saket Kumar Размещён: 16.03.2017 10:11

12 плюса

623 Репутация автора

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

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

<com.facebook.shimmer.ShimmerFrameLayout
     android:id=“@+id/shimmer_view_container”
     android:layout_width=“wrap_content”
     android:layout_height="wrap_content"
     shimmer:duration="1000">

 <here will be your content to display />

</com.facebook.shimmer.ShimmerFrameLayout>

И вот код Java для этого.

ShimmerFrameLayout shimmerContainer = (ShimmerFrameLayout) findViewById(R.id.shimmer_view_container);
shimmerContainer.startShimmerAnimation();

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

implementation 'com.facebook.shimmer:shimmer:0.1.0@aar'

Вот как это выглядит.Скриншот Android Shimmer

Автор: Zankrut Parmar Размещён: 26.02.2018 05:02
Вопросы из категории :
32x32