我正在使用ListView来显示与这些图像相关的一些图像和标题。我正在从互联网上获取图像。是否有一种方法可以延迟加载图像,以便在文本显示时,UI不会被阻止,图像在下载时显示?
图像总数不是固定的。
我正在使用ListView来显示与这些图像相关的一些图像和标题。我正在从互联网上获取图像。是否有一种方法可以延迟加载图像,以便在文本显示时,UI不会被阻止,图像在下载时显示?
图像总数不是固定的。
当前回答
我写了一篇教程,解释如何在列表视图中延迟加载图像。我详细讨论了回收和并发的问题。我还使用固定线程池来防止产生大量线程。
在Listview教程中延迟加载图像
其他回答
我用图像制作了一个懒惰列表(位于GitHub)的简单演示。
基本用途ImageLoader ImageLoader=新的ImageLoader(上下文)。。。imageLoader.DisplayImage(url,imageView);不要忘记添加对AndroidManifest.xml的以下权限:<uses permission android:name=“android.ppermission.INTERNET”/><uses permission android:name=“android.permission.WRITE_EXTERNAL_STORAGE”/>请只创建ImageLoader的一个实例,并在您的应用这样,图像缓存将更加高效。
这可能对某人有帮助。它在后台线程中下载图像。图像缓存在SD卡和内存中。缓存的实现非常简单,对于演示来说就足够了。我使用inSampleSize解码图像以减少内存消耗。我还尝试正确处理回收的视图。
另一种方法是通过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数组加载图像。此外,请始终检查内存是否泄漏,位图和可绘制文件通常占用大量内存。优化代码取决于您。
如果你想像Facebook一样显示Shimmer布局,有一个官方的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();
在渐变文件中添加此相关性。
implementation 'com.facebook.shimmer:shimmer:0.1.0@aar'
这是它的样子。
除了异步加载数据缓存外,您可能需要UI缓存,如setViewCacheSize
除了加载可见项数据外,您可能需要加载近似的可见项数据
AndroidX分页库是另一个选项,例如,您可以从SQLite数据库加载、缓存和显示10000000个项目到RecyclerView。参考PagedList
例子:假设列表视图可见项为[6,7,8,9,10],您可能需要加载[6,7,8,10]并预加载项[1,2,3,4,5]和[11,12,13,14,15],因为用户可能会滚动到前页或后页
更新:请注意,这个答案现在非常无效。垃圾回收器对SoftReference和WeakReference进行攻击,因此此代码不适用于新应用。(相反,请尝试其他答案中建议的通用图像加载器之类的库。)
感谢James提供的代码,感谢鲍龙提供的使用SoftReference的建议。我在James的代码上实现了SoftReference更改。不幸的是,SoftReferences导致我的图像被垃圾收集得太快。在我的情况下,没有SoftReference的东西很好,因为我的列表大小有限,图像也很小。
一年前有一场关于谷歌群组上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();
}