现在的位置: 首页 > 综合 > 正文

Android图片管理组件

2013年08月03日 ⁄ 综合 ⁄ 共 7174字 ⁄ 字号 评论关闭

Android图片管理组件

2013-03-07 10:00 by yueyueniao, 156 阅读, 0 评论, 收藏编辑

ImageManager2这个类具有异步从网络下载图片,从sd读取本地图片,内存缓存,硬盘缓存,图片使用动画渐现等功能,已经将其应用在包含大量图片的应用中一年多,没有出现oom。

Android程序常常会内存溢出,网上也有很多解决方案,如软引用,手动调用recycle等等。但经过我们实践发现这些方案,都没能起到很好的效果,我们的应用依然会出现很多oom,尤其我们的应用包含大量的图片。android3.0之后软引用基本已经失效,因为虚拟机只要碰到软引用就回收,所以带不来任何性能的提升。

我这里的解决方案是HandlerThread(异步加载)+LruCache(内存缓存)+DiskLruCache(硬盘缓存)

作为程序员,我也不多说,直接和大家共享我的代码,用代码交流更方便些。


源码demo地址:https://github.com/yueyueniao2012/multiimagechooser

 
复制代码
  1 package com.example.util;
2
3 import java.io.File;
4 import java.util.Iterator;
5 import java.util.LinkedList;
6 import java.util.Queue;
7 import java.util.Stack;
8
9 import org.apache.http.HttpEntity;
10 import org.apache.http.HttpResponse;
11 import org.apache.http.client.methods.HttpGet;
12 import org.apache.http.util.EntityUtils;
13
14 import android.app.ActivityManager;
15 import android.content.Context;
16 import android.graphics.Bitmap;
17 import android.graphics.BitmapFactory;
18 import android.graphics.drawable.BitmapDrawable;
19 import android.graphics.drawable.ColorDrawable;
20 import android.graphics.drawable.Drawable;
21 import android.graphics.drawable.TransitionDrawable;
22 import android.media.ThumbnailUtils;
23 import android.os.Handler;
24 import android.os.HandlerThread;
25 import android.os.Looper;
26 import android.os.Message;
27 import android.support.v4.util.LruCache;
28 import android.widget.ImageView;
29
30 import com.example.MyApplication;
31
32 /**
33 * 图片加载类
34 *
35 * @author 月月鸟
36 */
37 public class ImageManager2 {
38
39 private static ImageManager2 imageManager;
40 public LruCache<String, Bitmap> mMemoryCache;
41 private static final int DISK_CACHE_SIZE = 1024 * 1024 * 20; // 10MB
42 private static final String DISK_CACHE_SUBDIR = "thumbnails";
43 public DiskLruCache mDiskCache;
44 private static MyApplication myapp;
45
46 /** 图片加载队列,后进先出 */
47 private Stack<ImageRef> mImageQueue = new Stack<ImageRef>();
48
49 /** 图片请求队列,先进先出,用于存放已发送的请求。 */
50 private Queue<ImageRef> mRequestQueue = new LinkedList<ImageRef>();
51
52 /** 图片加载线程消息处理器 */
53 private Handler mImageLoaderHandler;
54
55 /** 图片加载线程是否就绪 */
56 private boolean mImageLoaderIdle = true;
57
58 /** 请求图片 */
59 private static final int MSG_REQUEST = 1;
60 /** 图片加载完成 */
61 private static final int MSG_REPLY = 2;
62 /** 中止图片加载线程 */
63 private static final int MSG_STOP = 3;
64 /** 如果图片是从网络加载,则应用渐显动画,如果从缓存读出则不应用动画 */
65 private boolean isFromNet = true;
66
67 /**
68 * 获取单例,只能在UI线程中使用。
69 *
70 * @param context
71 * @return
72 */
73 public static ImageManager2 from(Context context) {
74
75 // 如果不在ui线程中,则抛出异常
76 if (Looper.myLooper() != Looper.getMainLooper()) {
77 throw new RuntimeException("Cannot instantiate outside UI thread.");
78 }
79
80 if (myapp == null) {
81 myapp = (MyApplication) context.getApplicationContext();
82 }
83
84 if (imageManager == null) {
85 imageManager = new ImageManager2(myapp);
86 }
87
88 return imageManager;
89 }
90
91 /**
92 * 私有构造函数,保证单例模式
93 *
94 * @param context
95 */
96 private ImageManager2(Context context) {
97 int memClass = ((ActivityManager) context
98 .getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();
99 memClass = memClass > 32 ? 32 : memClass;
100 // 使用可用内存的1/8作为图片缓存
101 final int cacheSize = 1024 * 1024 * memClass / 8;
102
103 mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
104
105 protected int sizeOf(String key, Bitmap bitmap) {
106 return bitmap.getRowBytes() * bitmap.getHeight();
107 }
108
109 };
110
111 File cacheDir = DiskLruCache
112 .getDiskCacheDir(context, DISK_CACHE_SUBDIR);
113 mDiskCache = DiskLruCache.openCache(context, cacheDir, DISK_CACHE_SIZE);
114
115 }
116
117 /**
118 * 存放图片信息
119 */
120 class ImageRef {
121
122 /** 图片对应ImageView控件 */
123 ImageView imageView;
124 /** 图片URL地址 */
125 String url;
126 /** 图片缓存路径 */
127 String filePath;
128 /** 默认图资源ID */
129 int resId;
130 int width = 0;
131 int height = 0;
132
133 /**
134 * 构造函数
135 *
136 * @param imageView
137 * @param url
138 * @param resId
139 * @param filePath
140 */
141 ImageRef(ImageView imageView, String url, String filePath, int resId) {
142 this.imageView = imageView;
143 this.url = url;
144 this.filePath = filePath;
145 this.resId = resId;
146 }
147
148 ImageRef(ImageView imageView, String url, String filePath, int resId,
149 int width, int height) {
150 this.imageView = imageView;
151 this.url = url;
152 this.filePath = filePath;
153 this.resId = resId;
154 this.width = width;
155 this.height = height;
156 }
157
158 }
159
160 /**
161 * 显示图片
162 *
163 * @param imageView
164 * @param url
165 * @param resId
166 */
167 public void displayImage(ImageView imageView, String url, int resId) {
168 if (imageView == null) {
169 return;
170 }
171 if (imageView.getTag() != null
172 && imageView.getTag().toString().equals(url)) {
173 return;
174 }
175 if (resId >= 0) {
176 if (imageView.getBackground() == null) {
177 imageView.setBackgroundResource(resId);
178 }
179 imageView.setImageDrawable(null);
180
181 }
182 if (url == null || url.equals("")) {
183 return;
184 }
185
186 // 添加url tag
187 imageView.setTag(url);
188
189 // 读取map缓存
190 Bitmap bitmap = mMemoryCache.get(url);
191 if (bitmap != null) {
192 setImageBitmap(imageView, bitmap, false);
193 return;
194 }
195
196 // 生成文件名
197 String filePath = urlToFilePath(url);
198 if (filePath == null) {
199 return;
200 }
201
202 queueImage(new ImageRef(imageView, url, filePath, resId));
203 }
204
205 /**
206 * 显示图片固定大小图片的缩略图,一般用于显示列表的图片,可以大大减小内存使用
207 *
208 * @param imageView 加载图片的控件
209 * @param url 加载地址
210 * @param resId 默认图片
211 * @param width 指定宽度
212 * @param height 指定高度
213 */
214 public void displayImage(ImageView imageView, String url, int resId,
215 int width, int height) {
216 if (imageView == null) {
217 return;
218 }
219 if (resId >= 0) {
220
221 if (imageView.getBackground() == null) {
222 imageView.setBackgroundResource(resId);
223 }
224 imageView.setImageDrawable(null);
225
226 }
227 if (url == null || url.equals("")) {
228 return;
229 }
230
231 // 添加url tag
232 imageView.setTag(url);
233 // 读取map缓存
234 Bitmap bitmap = mMemoryCache.get(url + width + height);
235 if (bitmap != null) {
236 setImageBitmap(imageView, bitmap, false);
237 return;
238 }
239
240 // 生成文件名
241 String filePath = urlToFilePath(url);
242 if (filePath == null) {
243 return;
244 }
245
246 queueImage(new ImageRef(imageView, url, filePath, resId, width, height));
247 }
248
249 /**
250 * 入队,后进先出
251 *
252 * @param imageRef
253 */
254 public void queueImage(ImageRef imageRef) {
255
256 // 删除已有ImageView
257 Iterator<ImageRef> iterator = mImageQueue.iterator();
258 while (iterator.hasNext()) {
259 if (iterator.next().imageView == imageRef.imageView) {
260 iterator.remove();
261 }
262 }
263
264 // 添加请求
265 mImageQueue.push(imageRef);
266 sendRequest();
267 }
268
269 /**
270 * 发送请求
271 */
272 private void sendRequest() {
273
274 // 开启图片加载线程
275 if (mImageLoaderHandler == null) {
276 HandlerThread imageLoader = new HandlerThread("image_loader");
277 imageLoader.start();
278 mImageLoaderHandler = new ImageLoaderHandler(
279 imageLoader.getLooper());
280 }
281
282 // 发送请求
283 if (mImageLoaderIdle && mImageQueue.size() > 0) {
284 ImageRef imageRef = mImageQueue.pop();
285 Message message = mImageLoaderHandler.obtainMessage(MSG_REQUEST,
286 imageRef);
287 mImageLoaderHandler.sendMessage(message);
288 mImageLoaderIdle = false;
289 mRequestQueue.add(imageRef);
290 }
291 }
292
293 /**
294 * 图片加载线程
295 */
296 class ImageLoaderHandler extends Handler {
297
298 public ImageLoaderHandler(Looper looper) {
299 super(looper);
300 }
301
302 public void handleMessage(Message msg) {
303 if (msg == null)
304 return;
305
306 switch (msg.what) {
307
308 case MSG_REQUEST: // 收到请求
309 Bitmap bitmap = null;
310 Bitmap tBitmap = null;
311 if (msg.obj != null && msg.obj instanceof ImageRef) {
312
313 ImageRef imageRef = (ImageRef) msg.obj;
314 String url = imageRef.url;
315 if (url == null)
316 return;
317 // 如果本地url即读取sd相册图片,则直接读取,不用经过DiskCache
318 if (url.toLowerCase().contains("dcim")) {
319
320 tBitmap = null;
321 BitmapFactory.Options opt = new BitmapFactory.Options();
322 opt.inSampleSize = 1;
323 opt.inJustDecodeBounds = true;
324 BitmapFactory.decodeFile(url, opt);
325 int bitmapSize = opt.outHeight * opt.outWidth * 4;
326 opt.inSampleSize = bitmapSize / (1000 * 2000);
327 opt.inJustDec

抱歉!评论已关闭.