android中的图片缓冲区一直是个问题,包括超出虚拟机所分配的资源上限,重用已回收的bitmap等等,解决这个问题,每个人有每个人不同的方式,这里记录下我在项目中学到的的图片缓冲区的实现方式。
一个bitmap,可以携带一个属性,标识着这个bitmap最后的使用时间。而我们如果创建一个缓冲区,这个区里的bitmap数量是有一定限制的,否则就会出现内存溢出,超出了虚拟机分给程序的内存空间。而这个bitmap的最后使用时间就是确定删不删除这个bitmap的标志。
/**
* A Bitmap associated with its last modification date. This can be used to check
* whether the book covers should be downloaded again.
*/
public static class ExpiringBitmap {
public Bitmap bitmap;
public Calendar lastModified;
}
通过url去得到bitmap这个方法基本都是一致的,也许有的人写的强壮一点,功能会多一些。下边这个添加了附带cookies。其实多数时候是用不到的。
/**
* Loads an image from the specified URL with the specified cookie.
*
* @param url The URL of the image to load.
* @param cookie The cookie to use to load the image.
*
* @return The image at the specified URL or null if an error occured.
*/
public static ExpiringBitmap load(String url, String cookie) {
ExpiringBitmap expiring = new ExpiringBitmap();
final HttpGet get = new HttpGet(url);
if (cookie != null) get.setHeader("cookie", cookie);
HttpEntity entity = null;
try {
final HttpResponse response = HttpManager.execute(get);
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
setLastModified(expiring, response);
entity = response.getEntity();
InputStream in = null;
OutputStream out = null;
try {
in = entity.getContent();
if (FLAG_DECODE_BITMAP_WITH_SKIA) {
expiring.bitmap = BitmapFactory.decodeStream(in);
} else {
final ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
out = new BufferedOutputStream(dataStream, IOUtilities.IO_BUFFER_SIZE);
IOUtilities.copy(in, out);
out.flush();
final byte[] data = dataStream.toByteArray();
expiring.bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
}
} catch (IOException e) {
android.util.Log.e(LOG_TAG, "Could not load image from " + url, e);
} finally {
IOUtilities.closeStream(in);
IOUtilities.closeStream(out);
}
}
} catch (IOException e) {
android.util.Log.e(LOG_TAG, "Could not load image from " + url, e);
} finally {
if (entity != null) {
try {
entity.consumeContent();
} catch (IOException e) {
android.util.Log.e(LOG_TAG, "Could not load image from " + url, e);
}
}
}
return expiring;
}
在上边的方法里,可以看到有一个setLastModified(expiring, response);这个方法就是给bitmap这个数据添加上最后的修改时间,默认的会赋值成下载完成的时间,当二次访问的时候,我们可以重新赋值新的时间点。
private static void setLastModified(ExpiringBitmap expiring, HttpResponse response) {
expiring.lastModified = null;
final Header header = response.getFirstHeader("Last-Modified");
if (header == null) return;
if (sLastModifiedFormat == null) {
sLastModifiedFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z");
}
final Calendar calendar = GregorianCalendar.getInstance();
try {
calendar.setTime(sLastModifiedFormat.parse(header.getValue()));
expiring.lastModified = calendar;
} catch (ParseException e) {
// Ignore
}
}
从缓冲区中获取bitmap,这个方法基本都是给外部调用的,如果缓冲区存在这个bitmap,会返回,如果不存在就调用load(url)方法去获得这个bitmap数据并且放入缓冲区中。
/**
* Retrieves a drawable from the book covers cache, identified by the specified id.
* If the drawable does not exist in the cache, it is loaded and added to the cache.
* If the drawable cannot be added to the cache, the specified default drwaable is
* returned.
*
* @param id The id of the drawable to retrieve
* @param defaultCover The default drawable returned if no drawable can be found that
* matches the id
*
* @return The drawable identified by id or defaultCover
*/
public static FastBitmapDrawable getCachedCover(String id, FastBitmapDrawable defaultCover) {
FastBitmapDrawable drawable = null;
SoftReference<FastBitmapDrawable> reference = sArtCache.get(id);
if (reference != null) {
drawable = reference.get();
}
if (drawable == null) {
final Bitmap bitmap = loadCover(id);
if (bitmap != null) {
drawable = new FastBitmapDrawable(bitmap);
} else {
drawable = NULL_DRAWABLE;
}
sArtCache.put(id, new SoftReference<FastBitmapDrawable>(drawable));
}
return drawable == NULL_DRAWABLE ? defaultCover : drawable;
}
在文件的一开始,我们需要生成一个静态的缓冲区,一般都采用HashMap。
private static final HashMap<String, SoftReference<FastBitmapDrawable>> sArtCache =
new HashMap<String, SoftReference<FastBitmapDrawable>>();
从缓冲区中删除文件,从一个好的思路上来说,应该是对于缓冲区中所有文件进行一个对比,把那些长时间没有用到的文件删除。这给出的方法比较简单,就是删除所有的缓冲区文件。
/**
* Removes all the callbacks from the drawables stored in the memory cache. This
* method must be called from the onDestroy() method of any activity using the
* cached drawables. Failure to do so will result in the entire activity being
* leaked.
*/
public static void cleanupCache() {
for (SoftReference<FastBitmapDrawable> reference : sArtCache.values()) {
final FastBitmapDrawable drawable = reference.get();
if (drawable != null) drawable.setCallback(null);
}
}
这样一个简单的缓冲区文件基本雏形就有了,其他的需要自己按照自己的需求去写一下方法。或者进行一些有话,比如说这里提出的思路是每次读取一个bitmap时都会重置他的lastModified这个属性,然后在删除时,我们对这个属性进行遍历,删掉低于平均访问水瓶的bitmap,当然这个在以上程序代码中没有明确代码,因为以上代码是为了各自不同需求的基本代码,可以自己进行修改。对于前边这个思路的优化,可以删除掉lastModified这个属性,而采用一个队列的缓冲区方式,每次访问,都把这个bitmap先从队列中取出来,也就是删除,然后添加到队尾,这样的思路好处在于,当缓冲区多大,需要删除掉一些图片时,可以直接删除队首的若干个元素,节约了遍历所有元素的时间。
其他的对于缓冲区的使用还需要对线程进行一下控制,如果用的不好,也会出现一个线程的空间需求超出了分配给他的大小的异常。一般情况用线程池可以缓解这样的情况。
这些回头找时间再总结一下吧。
分享到:
相关推荐
在Android开发中,处理大量的图片资源时,常常会遇到内存溢出(Out Of Memory,简称OOM)的问题。这是因为Android系统为每个应用分配的内存有限,当加载过多或过大的图片时,很容易超出这个限制,导致应用崩溃。为了...
在Android应用开发中,特别是在构建类似新浪微博这样的社交网络平台时,图片缓冲技术是至关重要的。它涉及到用户体验、性能优化以及数据加载策略等多个方面。本文将深入探讨“Android新浪微博图片缓冲技术”的核心...
在内存中创建一个缓冲区,用于存储图片数据。可以创建一个TBitmap对象作为缓冲区,将图片加载到TBitmap的表面,这样在需要显示图片时,直接将TBitmap的内容绘制到TImage组件上即可。 2. **异步数据获取**: 为了...
总结来说,"android常用图片处理特效源码"这个资源包是一个学习Android图片特效处理的好材料,特别是对于高斯模糊算法的实现。通过对源码的研究,开发者不仅可以掌握基本的图片处理技术,还能了解到如何优化代码以...
SurfaceFlinger是负责将应用程序的各个图层合成到一个最终的帧缓冲区的过程,而WindowManager则管理着所有的窗口和视图。当触发截屏时,系统会调用SurfaceFlinger获取当前的屏幕截图,并将其保存为图像文件。 **二...
纹理对象是一个用于存储纹理数据的缓冲区1。 加载纹理数据:将图像数据加载到纹理对象中。在Android中,可以使用Bitmap类加载图片,并将其转换为OpenGL的纹理数据1。 设置纹理参数:为纹理对象设置一些...
这可能包括使用高效的纹理压缩格式、优化的顶点缓冲区、适当的批处理渲染等技术。 总的来说,这个"3D图片效果 android"项目涉及到了Android图形编程、3D建模与渲染、用户交互和性能优化等多个方面,为开发者提供了...
在加载新图片时,先加载到一个缓冲区,完成后再切换到另一个缓冲区显示,同时将旧缓冲区释放。这种方法可以避免屏幕闪烁,提高显示的连贯性。在图片加载中,双缓冲可以理解为内存缓存和本地缓存的结合。内存缓存用于...
在Android开发中,文件上传是一项常见的任务,尤其是图片或视频等多媒体内容的分享。当涉及到通过网络进行文件传输时,Socket通信是一种基础且灵活的方法。本篇将详细讲解如何在Android应用中实现基于Socket方式的...
- 请求数据:使用`mmap`映射内存到设备缓冲区,这样可以直接读取摄像头捕获的数据,提高效率。 - 数据读取:使用`read`或`poll`函数等待和接收数据。 2. **处理YUV数据**: - YUV是视频常用的色彩空间,分为多种...
而三重缓冲引入了第三个缓冲区,通过在多个缓冲区之间切换,使得GPU有更多的时间去完成渲染,从而避免了画面撕裂问题。 在异步加载方面,它涉及到的是数据或者资源在后台线程中预加载,而不阻塞主线程的运行。这种...
- 使用`BufferedReader`时,可以考虑设置适当的缓冲区大小以提高读取性能。 **扩展阅读:** - **Android操作JSON格式数据**:Android提供了Gson库、org.json库等工具来解析和生成JSON数据。 - **Android数据库操作*...
在NDK中,可能需要将Bitmap的数据转换为原生缓冲区(如uchar数组),以便进行处理。 10. **Android Studio集成NDK**:了解如何在Android Studio中配置和调试NDK项目,包括设置构建系统、添加本地库依赖、调试C/C++...
首先,`/dev/graphics/fb0`是Android设备上的帧缓冲区(Framebuffer)设备,它存储了当前屏幕显示的像素数据。帧缓冲区是操作系统用来直接控制显示设备的一种内存区域,其中包含了屏幕每一像素的RGB值。因此,我们...
SurfaceTexture是一个抽象接口,它与OpenGL ES纹理绑定,允许将硬件图形缓冲区的像素数据同步到GPU纹理。在相机应用中,我们可以设置SurfaceTexture作为相机预览的输出目标,这样相机捕获的每一帧图像都会自动更新到...
当一个缓冲区完成绘制后,它会被交换到显示位置,而另一个缓冲区则开始新的绘制过程。这样,用户看到的始终是已经完成绘制的内容,避免了半成品图像的闪烁,提升了用户体验。 在描述中提到的"一级和二级缓冲",可能...
本篇文章将深入探讨“Android硬解码MediaCodecDemo”,介绍如何利用MediaCodec进行硬解码操作,并处理在实际应用中可能遇到的crash、ANR(Application Not Responding)以及黑屏问题。 一、MediaCodec简介 ...
本文实例为大家分享了Android实现画板的具体代码,采用的技术是双缓冲技术,供大家参考,具体...定义一个内存中图片,将他作为缓冲区Bitmap cacheBitmap = null; 2).定义缓冲区Cache的Canvas对象 Canvas cacheCanvas
// 缓冲区 while (true) { int length = port.read(buffer); // 读取数据 if (length > 0) { String receivedData = new String(buffer, 0, length); // 处理接收到的数据 } // 发送数据 port.write("你的...