我正在使用ListView来显示与这些图像相关的一些图像和标题。我正在从互联网上获取图像。是否有一种方法可以延迟加载图像,以便在文本显示时,UI不会被阻止,图像在下载时显示?
图像总数不是固定的。
我正在使用ListView来显示与这些图像相关的一些图像和标题。我正在从互联网上获取图像。是否有一种方法可以延迟加载图像,以便在文本显示时,UI不会被阻止,图像在下载时显示?
图像总数不是固定的。
当前回答
更新:如果您正在寻找2020年由Kotlin Coroutines支持的解决方案,请尝试Coil。
Coil是Coroutine Image Loader的缩写。
特征
快速:Coil执行许多优化,包括内存和磁盘缓存、在内存中对图像进行下采样、重新使用位图、自动暂停/取消请求等。轻量级:Coil为您的APK添加了约2000个方法(适用于已经使用OkHttp和Coroutines的应用程序),这与毕加索不相上下,明显少于Glide和Fresco。易于使用:Coil的API利用了Kotlin的语言特性,以实现简单和最小的样板。现代:Coil首先是Kotlin,它使用了包括Coroutines、OkHttp、Okio和AndroidX Lifecycles在内的现代库。
渐变设置:
线圈在mavenCentral()上可用。
implementation("io.coil-kt:coil:1.0.0")
快速入门
要将图像加载到ImageView中,请使用加载扩展函数:
// URL
imageView.load("https://www.example.com/image.jpg")
// Resource
imageView.load(R.drawable.image)
// File
imageView.load(File("/path/to/image.jpg"))
或在后台线程上
// Coil (suspends the current coroutine; non-blocking and thread safe)
val request = ImageRequest.Builder(context)
.data(url)
.size(width, height)
.build()
val drawable = context.imageLoader.execute(request).drawable
您也可以从Picasso/Glide迁移
此处提供完整文档
其他回答
高性能加载器-在检查了这里建议的方法之后,我用了Ben的解决方案-
我意识到使用drawable比使用位图更快,所以我使用了drawable使用SoftReference很好,但它会使缓存的图像太频繁地被删除,所以我添加了一个保存图像引用的链接列表,防止图像被删除,直到达到预定义的大小为了打开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;
}
}
Novoda还有一个很棒的懒人图像加载库,许多应用程序如Songkick、Podio、SecretDJ和ImageSearch都使用其库。
他们的库托管在Github上,他们还有一个非常活跃的问题跟踪程序。他们的项目似乎也很活跃,在撰写回复时提交了超过300次。
我一直在使用新的Android Volley Library com.Android.Volley.toolbox.NetworkImageView中的NetworkImageView,它似乎工作得很好。显然,这是Google Play和其他新的Google应用程序中使用的相同视图。绝对值得一看。
Google I/O 2013凌空图像缓存教程开发者Google活动
我只想再添加一个很好的示例,XML适配器。由于它被谷歌使用,我也在使用相同的逻辑来避免OutOfMemory错误。
基本上,这个ImageDownloader就是你的答案(因为它涵盖了你的大部分需求)。有些也可以在其中实现。
URLImageViewHelper是一个非常棒的库,可以帮助您做到这一点。