对于大多数程序猿(码农)来说,一提到内存优化肯定都是比较头大,我也不例外,但是因为我们这个项目就我一个人做,出问题了也没有大牛解决,所以只能是自己硬着头皮上了。
言归正传,先交代一下事情的原因。楼主是做网盘项目的,从从未接触过分块上传、断点续传(以前一听断点续传也是头大)到勉强把分块上传下载做完,也是经历了好多痛苦的,但是,有一个事情一直是我不愿承认不想面对但却偏偏存在的问题,那就是下载的时候界面非常卡顿!是非常卡,不是一般的卡!小文件还好,感觉不出来,但是一超过100M就会非常卡甚至是ANR。没办法了,虽然我一直想逃避,但是这个总需要解决,只能硬着头皮来了!
简单介绍一下我们业务的一个“复杂”的地方,就是在下载每个数据块的时候,每个数据块之前都有一个自定义的文件头,里面包含了一些这个块的信息,已\r\n结束,所以在下载的时候不能直接每个块的直接下载,需要把这个头过滤掉。
首先我是这么做的,通过httpClient得到HttpEntity,在拷贝一份Entity,然后通过EntityUtils.toString获得数据内容(相信大多数使用HttpClient的都是这么做),然后从内容里截取出文件头,使用拷贝的entity获得输入流,跳过文件头长度再写文件,大致代码如下:
HttpEntity responseEntity = kscResponse.getResponse().getEntity(); HttpEntity responseEntityClone = responseEntity;//为什么拷贝一份? InputStream in = responseEntityClone.getContent(); String data = EntityUtils.toString(responseEntity); String customHeader = data.substring(0,data.indexOf("\n")+1); in.skip(customHeader.length()); //下面从流里写文件 ...
这里有一个会导致OOM的问题,就是EntityUtils.toString(responseEntity); 方法,我发现在上传叫大文件的时候会崩溃,我想是这个方法会把所有内容读取出来放到内存里,如果文件较大的话自然会崩溃,所以这个地方改成了自己写的InputStream2String方法,具体代码不写了,很常用,唯一的要点是当读取到一个size的时候(服务器限制的协议头最大长度)就跳出循环不在读取后面的数据,这样内存中最大也就是几k的数据,不会导致OOM了;但是,之前的卡顿情况还是每样解决。
然后开始各种查资料,各种“优化”之后(比如不要在循环里new 对象等),效果依然不理想。打开DDMS工具查看Allocation Tracker查看内存分配情况,发现还是下载的那个地方内存较大,其实我也知道HttpEntity responseEntityClone = responseEntity;拷贝这个地方可能会占用内存,但是也没办法啊,我需要先读取输入流把文件头取出来然后再写文件,但是读取输入流的时候就把responseEntity消耗掉了,后面也写不了文件了。后来突然想到BufferedReader 有一个readline方法,就是每次读取一行,已\r或者\n做标识,大喜之下尝试了一下,结果很令人失望,下载下来的文件和有损坏。。。绝望之下查看了下readline的源码,深受启发!修改了一下InputStream2String的代码,搞定!InputStream2String代码如下:
public static String InputStream2String(InputStream is) throws KuaipanException { if (is == null) { return null; } ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buf = new byte[BUFFER_SIZE]; int len = 0; int total = 0; try { while ((len = is.read(buf,0,1)) != -1) { byte ch = (byte)buf[0]; if (ch == '\n') { break; } baos.write(buf, 0, len); // total+=len; total++; // if(total >=MAX_COUNT) // break; } } catch (IOException e) { throw new KuaipanException(KuaipanException.IO_ERROR_CODE, "stream2String IOException", e); } String result = null; byte[] byteArray = baos.toByteArray(); int size = MAX_COUNT>byteArray.length?byteArray.length:MAX_COUNT; result = new String(byteArray,0,size); return result; }
先是一个个字符去读取,当读取到\n的时候,就不再读了,这样返回的数据刚好是文件头,后面自己也不需要自己去截取data.substring(0,data.indexOf("\n")+1);文件头了,同样,这个inputsream没有消耗完,下面可以接着写文件了,也不用in.skip(customHeader.length());了
测试了一下,下载的文件完全正确没有错误,而且卡顿现象有了很大的改善!
ps:本次优化就先告一段落,所谓优化,就是一个持续不断的过程,不是一蹴而就的。本次所有比以前有了很大改善,但是还是会感觉到有一点卡顿,慢慢来吧。。
如有错误不对的地方,敬请大牛指正!
相关推荐
内存泄漏是指程序在申请内存后,无法释放已申请的内存空间,一次小的内存泄漏可能不会立即显现问题,但随着时间的推移,内存消耗会逐渐增大,最终可能导致系统资源耗尽。 在Android的Native层,由于C++代码的特性,...
总的来说,这个"Android zxing二维码扫描个人优化版(第二版)"是针对原ZXing库的一次深度定制,旨在提供更加稳定、高效且易用的二维码扫描解决方案。无论是对普通用户还是开发者来说,这样的优化都有助于提升扫描...
- 启动Service:通过`startService()`启动,仅执行一次任务,不需要返回结果。 - 绑定Service:通过`bindService()`绑定,可以多次调用,用于与Service进行交互。 2. **多线程下载**: - 多线程的目的:提高下载...
流式处理允许数据逐块读取和写入,而不需要一次性加载整个文件到内存,这样显著降低了对内存的需求。异步加载则避免了因为网络操作阻塞主线程,提高用户体验,防止出现“应用无响应”(ANR)的情况。Android提供了...
为了实现断点续传,我们需要保存当前的下载状态,这包括已下载的文件大小和最后一次下载的字节位置。 这里,Sqlite数据库发挥了关键作用。Sqlite是Android内置的关系型数据库,用于持久化数据。我们可以创建一个表...
本文将基于标题“记一次典型的因应用使用内存不合理而频发的性能问题”展开讨论,探讨如何识别和解决内存使用不合理的性能问题。首先,我们理解内存管理是关乎程序运行速度、稳定性和资源效率的重要方面,特别是在大...
1. **多线程原理**:在传统的单线程下载中,数据流一次性从服务器获取到客户端,如果网络不稳定或速度慢,下载过程就会很慢。多线程下载则是将大文件分成多个小部分,每个部分由一个单独的线程负责下载,这样可以...
在Android应用开发中,优化绘制过程对于提供流畅的用户体验至关重要。本文将探讨Android系统显示原理、性能分析工具、布局优化、避免过度绘制、合理的刷新机制、提升动画性能以及卡顿监控方案。 一、Android系统...
传统的单线程下载方式会一次性请求整个文件,当文件较大时,速度可能受限于网络带宽。而多线程下载则是将文件分割成多个部分,同时启动多个下载任务,每个任务负责下载一个部分,这样可以充分利用网络资源,加快下载...
在单线程下载中,文件通常被一次性完整地下载,而在多线程下载中,文件会被分割成多个部分,每个部分由单独的线程负责下载。这样可以同时利用多个网络连接,提高下载速度,并且在某个线程出现问题时,其他线程仍可...
在单线程下载中,数据是从服务器一次性传输到客户端,如果文件较大,这可能会导致用户等待时间过长,用户体验不佳。为了解决这个问题,开发者通常采用多线程下载技术。通过将大文件分割成多个小部分,每个部分在一个...
客户端将已上传的数据存储,并在下一次上传时告知服务器已上传的部分。 - **实现**: - **创建临时文件**:客户端首先在本地创建一个临时文件,用于存储待上传的数据。 - **分段上传**:将大文件切分为多个小块,...
5. 性能优化:Android Studio提供了多种性能优化工具,如Lint检查、内存分析器等,开发者可以根据这些工具的提示优化代码,提升应用性能。 四、学习与进阶 对于初学者,通过分析"ZMath"的源码,可以学习到Android...
创建一个服务,可以确保下载过程不会因用户界面关闭而中断,提高了下载的可靠性。 2. **线程与线程池** 在Android中,为了防止UI线程被阻塞,下载操作应该在后台线程中进行。线程池可以有效管理多个下载任务,避免...
� 采用了对有限内存、电池和 CPU 优化过的虚拟机 Dalvik , Android 的运行速度比想象的要快很多。 � 运营商(中国移动等)的大力支持,产业链条的热捧。 � 良好的盈利模式( 3/7 开),产业链条的各方:运营商、...
- 需要优化内存管理,避免一次性加载整个大文件到内存,防止内存溢出。 3. **断点续传实现**: - **记录当前位置**:在上传过程中,记录已上传的文件偏移量,以便在中断后恢复时作为起点。 - **分块传输**:将大...
通过这个工具,开发者可以实时查看哪些应用或服务占用了大量内存,从而进行内存优化。 4. **闪退日志14.13、闪退日志、闪退ums_1204** - 这些日志文件分别记录了不同时间点或特定场景下的应用闪退事件,可能与内存...
- 为了避免内存溢出,下载过程中应适当分块,避免一次性加载大量数据。 - 对于大文件,应考虑分段保存,避免因应用崩溃或意外情况导致整个文件丢失。 - 为避免下载过程中的数据不一致,每次写入文件前检查文件...
此外,为了提供良好的用户体验,还需要考虑性能优化,比如使用异步加载策略,避免一次性加载过多内容导致内存消耗过大。 接下来是"文件上传下载功能"。在Android中,文件上传通常通过HTTP或HTTPS协议完成,可以使用...