ListView中的图像延迟加载

los*_*sit 1881 url android listview image universal-image-loader

我使用a ListView来显示与这些图像相关的一些图像和标题.我从互联网上获取图像.有没有办法延迟加载图像,以便文本显示时,UI不会被锁定,图像会在下载时显示?

图像总数不固定.

Jam*_*son 1069

这是我创建的用于保存我的应用当前正在显示的图像的内容.请注意,这里使用的"Log"对象是围绕Android内部最终Log类的自定义包装器.

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为你应该使用SoftReferences,这样你的程序永远不会导致OutOfMemoryException.由于GC可以在堆大小增加时清除软引用...您可以管理自己的生成,就像几秒钟后您可以将图像放到该列表中,在加载之前,您应检查是否存在图像然后再不下载而是收集它从该列表中,并将其返回到您的softref列表,并在一段时间后,您可以清除您的硬件列表:) (101认同)
  • 谷歌货架项目是一个很好的例子,看看他们是如何做的http://code.google.com/p/shelves/ (35认同)
  • 当drawableMap包含图像时,不要错过返回...没有启动提取线程吗? (11认同)
  • 没有人听说过`LRU Cache` http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html (9认同)
  • 这段代码有几个问题.首先,您应该缓存Drawables,这将导致内存泄漏:http://stackoverflow.com/questions/7648740/consequences-of-drawable-setcallbacknull.其次,缓存本身永远不会被清除,因此它将永远增长,这是另一个内存泄漏. (4认同)
  • @James A Wilson...我在哪里将它与列表视图连接以将图像显示为缩略图??ma newbie android dev...如果有人能告诉我,请告诉我 (3认同)
  • 这会导致图像在列表视图中获得错误的图像源。例如,我有图标 1 、 2 和 3 。使用这个可绘制管理器类时,我的列表显示图标 1 和两个 3 图标。有谁知道这是如何从上面的确切代码中解决的? (3认同)
  • 我使用这个类从 URL 下载我的图像列表,然后我使用下面的代码清除缓存,一切似乎都很好![清除缓存 - 这里](http://stackoverflow.com/questions/6898090/how-to-clear-cache-android) (3认同)
  • 为什么不将“this”传递给您的记录器包装器?然后你不必到处调用 getClass().getSimpleName() (3认同)
  • 只观察:你正在开始一个未知数量的线程.我建议使用具有固定线程数的Executor,或AsyncTask(它们也使用单个Executor) (2认同)

Fed*_*dor 1018

我用图像做了一个懒惰列表(位于GitHub)的简单演示.这可能对某人有帮助.它在后台线程中下载图像.图像正在缓存在SD卡和内存中.缓存实现非常简单,仅适用于演示.我用inSampleSize解码图像以减少内存消耗.我也尝试正确处理回收的视图.

替代文字

  • 我想为像我这样的新手添加如果你想将这个代码添加到你自己的项目中,你必须在清单中添加外部缓存权限.谢谢 (63认同)
  • 谢谢,我在我的项目中几乎无处不在地使用了稍微修改过的代码版本:http://code.google.com/p/vimeoid/source/browse/apk/src/com/fedorvlasov/lazylist/ImageLoader. java的 (6认同)
  • 有一个bug,有时会被解雇:10-13 09:58:46.738:ERROR/AndroidRuntime(24250):未捕获的处理程序:由于未捕获的异常导致主要退出10-13 09:58:46.768:ERROR/AndroidRuntime(24250) :java.lang.ArrayIndexOutOfBoundsException:数组索引超出范围:0 10-13 09:58:46.768:ERROR/AndroidRuntime(24250):at java.util.Vector.elementAt(Vector.java:331)10-13 09: 58:46.768:ERROR/AndroidRuntime(24250):at java.util.Vector.get(Vector.java:445)10-13 09:58:46.768:ERROR/AndroidRuntime(24250):at com.my.app.image .ImageLoader $ PhotosQueue.Clean(ImageLoader.java:91) (3认同)
  • 有没有人看过Gilles Debunne的代码作为替代品.我看到的两个巨大差异是1)在内存缓存与SD卡和2)使用AsyncTasks而不是线程池.http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html (2认同)

nos*_*a13 548

我推荐开源仪器Universal Image Loader.它最初基于Fedor Vlasov的项目LazyList,并从那时起得到了极大的改进.

  • 多线程图像加载
  • 可以广泛调整ImageLoader的配置(线程执行器,下载器,解码器,内存和光盘缓存,显示图像选项等)
  • 在内存和/或设备的文件系统(或SD卡)上进行图像缓存的可能性
  • 可以"监听"加载过程
  • 可以使用分离的选项自定义每个显示图像调用
  • 小工具支持
  • Android 2.0+支持

  • 如果你正在寻找伟大的"图像加载"代码,它的创造者将其作为他的宝贝(不仅是一次性解决方案)对待和维护,你只是找到它; Nostra (15认同)
  • 在阅读官方的android文档并尝试自己做这些东西后,我很确定这个库是最终所有图像加载.不能upvote足够. (2认同)

Tho*_*hle 155

Multithreading For Performance,Gilles Debunne的教程.

这是来自Android开发者博客.建议的代码使用:

  • AsyncTasks.
  • 坚硬,有限的尺寸FIFO cache.
  • 一个柔软,易于使用的garbage collect缓存.
  • 下载时的占位符 Drawable.

在此输入图像描述

  • 它在2.1中也可以正常工作.只是不要使用AndroidHttpClient. (9认同)
  • @thomas-ahle 谢谢,我看到 AndroidHttpClient 在 2.1 中出现错误,因为它是从 2.2 实现的,但并没有真正尝试找到其他东西来替换它。 (3认同)
  • @Adina你是对的,我忘记了.但是,配方中没有任何东西可以用普通的HttpClient完成. (3认同)

Tal*_*tle 106

更新:请注意,这个答案现在非常无效.垃圾收集器对SoftReference和WeakReference采取积极行动,因此此代码不适用于新应用程序. (相反,尝试像其他答案中提到的Universal Image Loader这样的库.)

感谢James的代码,以及Bao-Long建议使用SoftReference.我在James的代码上实现了SoftReference的更改.不幸的是,SoftReferences导致我的图像垃圾收集过快.在我的情况下没有SoftReference的东西很好,因为我的列表大小有限,我的图像很小.

一年前有关于google群组的SoftReferences的讨论:链接到线程.作为过早垃圾收集的解决方案,他们建议使用dalvik.system.VMRuntime.setMinimumHeapSize()手动设置VM堆大小,这对我来说不是很有吸引力.

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();
}
Run Code Online (Sandbox Code Playgroud)

  • 你可以创造像硬代和软代的世代.你可以修复一个时间清除缓存将清除所有未在3秒内访问的图像..你可以看看谷歌货架项目 (2认同)

Ash*_*hok 95

毕加索

使用杰克沃顿的毕加索图书馆.(一个完美的ImageLoading Library构成ActionBarSherlock的开发者)

适用于Android的强大图像下载和缓存库.

图像为Android应用程序添加了急需的上下文和视觉风格.Picasso允许在您的应用程序中轻松加载图像 - 通常在一行代码中!

Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
Run Code Online (Sandbox Code Playgroud)

Android上图像加载的许多常见缺陷由Picasso自动处理:

在适配器中处理ImageView回收和下载取消.复杂的图像转换,内存使用最少.自动内存和磁盘缓存.

毕加索杰克沃顿图书馆

滑行

Glide是一个快速高效的Android开源媒体管理框架,它将媒体解码,内存和磁盘缓存以及资源池包装成一个简单易用的界面.

Glide支持提取,解码和显示视频静止图像,图像和动画GIF.Glide包含一个灵活的api,允许开发人员插入几乎任何网络堆栈.默认情况下,Glide使用基于HttpUrlConnection的自定义堆栈,但也包括插入Google的Volley项目或Square的OkHttp库的实用程序库.

Glide.with(this).load("http://goo.gl/h8qOq7").into(imageView);
Run Code Online (Sandbox Code Playgroud)

Glide主要关注的是尽可能平滑和快速地滚动任何类型的图像列表,但Glide对于您需要获取,调整大小和显示远程图像的几乎任何情况都是有效的.

滑翔图像加载库

Fresco by Facebook

Fresco是一个功能强大的系统,用于在Android应用程序中显示图像.

Fresco负责图像加载和显示,因此您不必这样做.它将从网络,本地存储或本地资源加载图像,并显示占位符,直到图像到达.它有两级缓存; 一个在内存中,另一个在内部存储中.

Fresco Github

在Android 4.x及更低版本中,Fresco将图像放在Android内存的特殊区域.这可以让您的应用程序运行得更快 - 并且更少经常遭受可怕的OutOfMemoryError.

壁画文件


Asa*_*ssi 81

高性能加载器 - 在检查了这里建议的方法后,我使用Ben的解决方案进行了一些更改 -

  1. 我意识到使用drawables比使用位图更快,所以我使用drawables代替

  2. 使用SoftReference非常棒,但它会使缓存的图像被删除得太频繁,因此我添加了一个包含图像引用的链接列表,防止图像被删除,直到达到预定义的大小

  3. 要打开InputStream,我使用java.net.URLConnection,它允许我使用Web缓存(您需要先设置响应缓存,但这是另一个故事)

我的代码:

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;
}
}
Run Code Online (Sandbox Code Playgroud)

  • @MichaelReed,如果您是Eclipse用户,我建议使用Ctrl-Shift-O(字母O,而不是数字0).它可以自动完成添加导入的过程并为您组织它们.如果您使用的是Mac,请使用Command-Shift-O代替. (8认同)
  • 如果它节省了别人的时间:`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;` (4认同)

too*_*o42 77

我已经关注了这个Android培训,我认为它在不阻止主UI的情况下下载图像方面表现非常出色.它还处理缓存和处理滚动许多图像:高效加载大位图


chi*_*ada 63

1. 毕加索允许在您的应用程序中轻松加载图像 - 通常只需一行代码!

使用Gradle:

implementation 'com.squareup.picasso:picasso:2.71828'
Run Code Online (Sandbox Code Playgroud)

只需一行代码!

Picasso.get().load("http://i.imgur.com/DvpvklR.png").into(imageView);
Run Code Online (Sandbox Code Playgroud)

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'
}
Run Code Online (Sandbox Code Playgroud)

//对于一个简单的视图:

  Glide.with(this).load("http://i.imgur.com/DvpvklR.png").into(imageView);
Run Code Online (Sandbox Code Playgroud)

3. fresco 是一个功能强大的系统,用于在Android应用程序中显示图像.Fresco负责图像加载和显示,因此您不必这样做.

Fresco入门


Ben*_*ijl 51

我写了一个教程,解释了如何在列表视图中进行延迟加载图像.我详细介绍了回收和并发问题.我还使用固定的线程池来防止产生大量线程.

在Listview教程中延迟加载图像


jas*_*ins 40

我这样做的方法是启动一个线程来在后台下载图像,并为每个列表项提供一个回调.当图像下载完成后,它会调用回调来更新列表项的视图.

但是,当您回收视图时,此方法不能很好地工作.

  • 为每个图像启动新线程不是一个有效的解决方案.你可以在内存中结束很多线程并冻结UI. (13认同)

Ars*_*war 31

我只想添加一个更好的例子,XML Adapters.因为它被谷歌使用,我也使用相同的逻辑来避免OutOfMemory错误.

基本上这个ImageDownloader是你的答案(因为它涵盖了你的大多数要求).有些你也可以实现.

  • ImageDownloader 类未得到遵守:请参阅下面的解决方案 http://code.google.com/p/parleys-android-nextgen/issues/detail?id=1 (3认同)

小智 28

我一直在使用新的Android Volley Library中的NetworkImageView com.android.volley.toolbox.NetworkImageView,它似乎运行得很好.显然,这与Google Play和其他新的Google应用程序中使用的视图相同.绝对值得一试.

  • 我认为这是最好的解决方案 - 其他答案很旧 - 截击速度非常快,并与 jake warthons disklrucache 结合,这是一个完美的解决方案 - 我尝试了很多其他解决方案,但没有一个像截击一样稳定和快速 (2认同)

how*_*ttl 28

这是Android上的一个常见问题,许多人已经通过多种方式解决了这个问题.在我看来,我见过的最好的解决方案是相对较新的名为Picasso的库.以下是亮点:

  • 开源,但为首Jake WhartonActionBarSherlock成名.
  • 使用一行代码从网络或应用程序资源异步加载图像
  • 自动ListView检测
  • 自动磁盘和内存缓存
  • 可以做自定义转换
  • 大量可配置选项
  • 超级简单的API
  • 经常更新


Rah*_*wat 25

那么,来自互联网的图像加载时间有很多解决方案.您也可以使用Android-Query库.它将为您提供所有必需的活动.确保您要执行的操作并阅读库wiki页面.并解决图像加载限制.

这是我的代码:

@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;
}
Run Code Online (Sandbox Code Playgroud)

它应该解决你的延迟加载问题.


Rit*_*bey 24

我认为这个问题在Android开发人员中非常受欢迎,并且有很多这样的图书馆声称可以解决这个问题,但其中只有少数似乎是标记.AQuery是一个这样的库,但它在各个方面都比大多数都好,值得一试.


Gir*_*tel 21

你必须尝试这种通用装载机是最好的.在懒惰加载完成许多RnD之后我正在使用它.

通用图像加载器

特征

  • 多线程图像加载(异步或同步)
  • ImageLoader配置的广泛定制(线程执行器,下载器,解码器,内存和磁盘缓存,显示图像选项等)
  • 每个显示图像调用的许多自定义选项(存根图像,缓存切换,解码选项,位图处理和显示等)
  • 内存和/或磁盘上的图像缓存(设备的文件系统或SD卡)
  • 听力加载过程(包括下载进度)

Android 2.0+支持

在此输入图像描述


Pat*_*NLT 20

看一下Shutterbug,Applidium的轻量级SDWebImage(iOS上的一个不错的库)到Android的端口.它支持异步缓存,存储失败的URL,很好地处理并发,并包含有用的子类.

拉动请求(和错误报告)也是受欢迎的!


yan*_*nko 16

DroidPartsImageFetcher,需要零配置才能开始.

  • 使用磁盘和内存中最近最少使用(LRU)缓存.
  • 有效地解码图像.
  • 支持修改后台线程中的位图.
  • 有简单的交叉淡入淡出.
  • 有图像加载进度回调.

克隆DroidPartsGram为例:

在此输入图像描述


Bij*_*ala 16

对于一个犹豫不决的人来说,只是一个快速的提示,关于用于延迟加载图像的库:

有四种基本方式.

  1. DIY =>不是最好的解决方案,但对于一些图像,如果你想没有使用其他库的麻烦

  2. Volley的Lazy Loading库=>来自android的玩家.它很好,但是文档记录很少,因此使用起来很困难.

  3. Picasso:一个简单的解决方案,你甚至可以指定你想要带来的确切图像大小.它使用起来非常简单,但对于那些必须处理大量图像的应用来说可能不是很"高效".

  4. UIL:延迟加载图像的最佳方法.您可以缓存图像(当然需要权限),初始化加载程序一次,然后完成工作.到目前为止我见过的最成熟的异步图像加载库.


Soh*_*ham 15

Novoda还有一个很棒的懒人图像加载库,很多应用程序如Songkick,Podio,SecretDJ和ImageSearch都使用他们的库.

他们的图书馆托管这里 Github上,他们有一个非常活跃的问题跟踪器为好.他们的项目似乎也相当活跃,在撰写此回复时有超过300次提交.

  • 实际上,Novoda 是一个很棒的库,但是……有时您不需要一个庞大的库,只需要一个简单的解决方案方法。这就是为什么 Github 中的 LazyList 如此出色的原因,如果您的应用程序仅在 listView 中显示图像并且不是您应用程序的主要功能,那么我更喜欢使用更轻松的另一个活动。否则,如果您知道您将不得不经常使用并且是核心的一部分,请尝试使用 Novoda。 (2认同)

Nic*_*lle 13

检查我的LazyList分支.基本上,我通过延迟ImageView的调用来改进LazyList并创建两个方法:

  1. 当你需要输入"加载图像......"之类的东西时
  2. 当您需要显示下载的图像时.

我还通过在此对象中实现单例来改进ImageLoader .


Zan*_*mar 12

如果你想显示像Facebook这样的Shimmer布局,那么就有一个官方的facebok库.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>
Run Code Online (Sandbox Code Playgroud)

这是它的java代码.

ShimmerFrameLayout shimmerContainer = (ShimmerFrameLayout) findViewById(R.id.shimmer_view_container);
shimmerContainer.startShimmerAnimation();
Run Code Online (Sandbox Code Playgroud)

在gradle文件中添加此依赖项.

implementation 'com.facebook.shimmer:shimmer:0.1.0@aar'
Run Code Online (Sandbox Code Playgroud)

这是它的样子.Shimmer Android截图


AKb*_*ber 11

以上所有代码都有自己的价值,但根据我的个人经验,只需尝试毕加索.

Picasso 是专门用于此目的的库,实际上它将自动管理缓存和所有其他网络操作.您将不得不在项目中添加库,只需编写一行代码即可从远程URL加载图像.

请访问:http://code.tutsplus.com/tutorials/android-sdk-working-with-picasso--cms-22149


小智 9

使用滑动库.它对我有用,也适用于你的代码.它既适用于图像,也适用于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);
}
Run Code Online (Sandbox Code Playgroud)


Pra*_*asa 7

我可以推荐一种不同于魅力的方式:Android查询.

您可以从此处下载该JAR文件

AQuery androidAQuery = new AQuery(this);
Run Code Online (Sandbox Code Playgroud)

举个例子:

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

它非常快速和准确,使用它你可以找到更多的功能,如加载时的动画,获取位图(如果需要)等.


use*_*311 7

Aquery一试.它具有非常简单的方法来异步加载和缓存图像.


小智 7

URLImageViewHelper是一个很棒的库,可以帮助您实现这一目标.


小智 5

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;
 }
}
Run Code Online (Sandbox Code Playgroud)


j2e*_*nue 5

我遇到了这个问题并实现了 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);
Run Code Online (Sandbox Code Playgroud)

这是缓存的理想代码,然后在检索 Web 图像时在适配器的 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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Chi*_*ori 5

您可以尝试使用Aquery Android库延迟加载图像和列表视图...下面的代码可以帮助您.....从这里下载库

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


归档时间:

查看次数:

536159 次

最近记录:

5 年,11 月 前