Android中ListView图片懒加载的实现方法

Android中ListView图片懒加载的实现方法

技术背景

在Android开发中,当ListView需要显示大量图片时,一次性加载所有图片会导致内存占用过高,甚至出现OOM(OutOfMemory)错误,同时也会影响列表的滚动流畅性。图片懒加载技术可以在需要显示图片时再进行加载,从而优化内存使用和提升用户体验。

实现步骤

1. 自定义DrawableManager类

可以创建一个DrawableManager类来管理图片的加载和缓存,以下是示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Map;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.widget.ImageView;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

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);
}

try {
InputStream is = fetch(urlString);
Drawable drawable = Drawable.createFromStream(is, "src");

if (drawable != null) {
drawableMap.put(urlString, drawable);
}
return drawable;
} catch (MalformedURLException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
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(Looper.getMainLooper()) {
@Override
public void handleMessage(Message message) {
imageView.setImageDrawable((Drawable) message.obj);
}
};

Thread thread = new Thread() {
@Override
public void run() {
Drawable drawable = fetchDrawable(urlString);
Message message = handler.obtainMessage(1, drawable);
handler.sendMessage(message);
}
};
thread.start();
}

private InputStream fetch(String urlString) throws MalformedURLException, IOException {
HttpClient httpClient = new DefaultHttpClient();
HttpGet request = new HttpGet(urlString);
HttpResponse response = httpClient.execute(request);
return response.getEntity().getContent();
}
}

2. 使用第三方库

  • Picasso
    • 添加依赖:在build.gradle中添加以下代码:
1
implementation 'com.squareup.picasso:picasso:(insert latest version)'
- **使用方法**:
1
Picasso.get().load("http://i.imgur.com/DvpvklR.png").into(imageView);
  • Glide
    • 添加依赖:在build.gradle中添加以下代码:
1
2
3
4
5
6
7
8
9
repositories {
mavenCentral()
google()
}

dependencies {
implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
}
- **使用方法**:
1
Glide.with(this).load("http://i.imgur.com/DvpvklR.png").into(imageView);
  • Fresco
    • 添加依赖:按照Fresco文档进行配置。
    • 使用方法:参考Fresco的官方文档

3. 手动实现懒加载

可以在ListView的适配器的getView方法中,通过开启线程的方式在后台下载图片,并在图片下载完成后更新UI。以下是示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@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);
final String imageUrl = "http://www.vikispot.com/z/images/vikispot/android-w.png";

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

return v;
}

最佳实践

  • 使用缓存:将已经下载的图片进行缓存,避免重复下载,减少网络流量和加载时间。可以使用内存缓存(如LruCache)和磁盘缓存。
  • 控制线程数量:避免创建过多的线程,以免影响性能。可以使用线程池来管理线程。
  • 处理图片回收:在ListView滚动时,及时回收不再显示的图片,释放内存。

常见问题

  • OOM错误:由于图片占用内存过大导致。可以通过压缩图片、使用缓存和及时回收图片等方式来解决。
  • 图片加载闪烁:可能是由于图片重复加载或ListView滚动时图片回收不及时导致。可以通过在下载图片时检查ImageView是否已经被复用,以及使用占位图来解决。
  • 网络问题:网络不稳定或图片地址错误可能导致图片加载失败。可以在代码中添加错误处理机制,如显示默认图片或重试下载。

Android中ListView图片懒加载的实现方法
https://119291.xyz/posts/android-listview-image-lazy-loading/
作者
ww
发布于
2025年5月22日
许可协议