问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

在Android开发中,有哪些好的内存优化方式

发布网友 发布时间:2022-04-23 01:34

我来回答

4个回答

热心网友 时间:2022-05-14 13:01

内存优化
Coding
Bitmap
ListView
SoftReference & WeakReference
UI

2.1 Coding
Tip 1:使用优化过的数据容器。
如SparseArray,SparseBooleanArray,LongSparseArray,代替HashMap
前提:Key为Integer类型
原因:
HashMap 是内存低效的,因为每一个mapping都需要单独的entry(如下图)。
每个元素多占用8byte内存(多了next和hash两个成员变量)。AutoBox【int转Integer,导致产生另一个对象】也会额外加4byte。Entry对象本身至少16byte。
SparseArray可以避免AutoBox,查找方法为二分查找,效率比HashMap低一些,但百量级以内性能差距不大。

HashMap<Integer, E> hashMap = new HashMap<Integer, E>();
替换为
SparseArray<E> sparseArray = new SparseArray<E>();、
Tip 2:使用IntentService替代Service。
IntentService优势:
•新开线程;
•顺序处理Intent;
•执行完自动退出。
说明:
Service是一个没有界面的服务,但其实它不是后台的,所有的代码默认在UI线程执行。若要执行耗时操作,需要新开线程或者使用AsyncTask。
IntentService继承自Service,所以它也是一个服务。
IntentService使用队列的方式将请求的Intent加入队列,然后开启一个worker thread(线程)来处理队列中的Intent,对于异步的startService请求,IntentService会处理完成一个之后再处理第二个,每一个请求都会在一个单独的worker thread中处理,不会阻塞应用程序的主线程。
IntentService与Service区别:
1,Service默认在UI线程执行;而IntentService的onHandleIntent方法在后台执行。
2,Service在start后,如果没有手动stop会一直存在;而IntentService在执行完后自动退出。
Tip 3:尽量避免使用Enum。
枚举相对于静态常量来说,需要两倍甚至更多的内存。如下是Enum的类型定义:

Tip 4:使用混淆器移除不必要的代码。
ProGuard工具通过移除无用代码,使用语意模糊来保留类,字段和方法来压缩,优化和混淆代码。可以使你的代码更加完整,更少的RAM 映射页。
Tip 5:尽量不要因一两个特性而使用大体积类库。
Tip 6:频繁修改时使用 StringBuffer(Thread-Safe)或 StringBuilder(Thread-Unsafe)。
使用String修改字符串时,若修改后字符串在字符串常量区不存在,便会新生成一个String对象。
Tip 7: 对于常量,请尽量使用static final。
如果使用final定义常量之后,会减少编译器在类生成时初始化<clinit>方法调用时对常量的存储,对于int型常量,将会直接使用其数值来进行替换,而对于String对象将会使用相对廉价的“string constant”指令来替换字段查找表。虽然这个方法并不完全对所有类型都有效,但是,将常量声明为static final绝对是一个好的做法。
Tip 8:对象不用时最好显式置为Null。
对象不用时最好显式置为Null可以减少GC开销。
警惕:静态变量引起内存泄露

这段代码中有一个静态的Resources对象。代码片段mResources = this.getResources()对Resources对象进行了初始化。这时Resources对象拥有了当前Activity对象的引用,Activity又引用了整个页面中所有的对象。
如果当前的Activity被重新创建(比如横竖屏切换,默认情况下整个Activity会被重新创建),由于Resources引用了第一次创建的Activity,就会导致第一次创建的Activity不能被垃圾回收器回收,从而导致第一次创建的Activity中的所有对象都不能被回收。这个时候,一部分内存就浪费掉了。
警惕:使用Activity Context引起内存泄露。
应该尽量使用Application Context。
在Android中,Application Context的生命周期和应用的生命周期一样长,而不是取决于某个Activity的生命周期。如果想保持一个长期生命的对象,并且这个对象需要一个Context,就可以使用Application对象。
看使用的周期是否在activity周期内,如果超出,必须用application;常见的情景包括:AsyncTask,Thread,第三方库初始化等等。
还有些情景,只能用activity:比如,对话框,各种View,需要startActivity的等。总之,尽可能使用Application。

上面由于静态变量导致的内存泄露问题,可以修改如下:

2.2 Bitmap
Tip:捕获异常

因为Bitmap是吃内存大户,为了避免应用在分配Bitmap内存的时候出现OutOfMemory异常以后Crash掉,需要特别注意实例化Bitmap部分的代码。通常,在实例化Bitmap的代码中,一定要对OutOfMemory异常进行捕获。
OutOfMemoryError是一种Error,而不是Exception。
Tip:缓存通用的图像【该方法测试无效】
应用场景:默认头像。有时候,可能需要在一个Activity里多次用到同一张图片。比如一个Activity会展示一些用户的头像列表,而如果用户没有设置头像的话,则会显示一个默认头像,而这个头像是位于应用程序本身的资源文件中的。
此方法无效!因为:
因为Android自带资源文件缓存机制:
在Resource.java类中有LongSparseArray<WeakReference<Drawable.ConstantState> > mDrawableCache
每次会new 一个Drawable,但内部bitmap还是指向cache中的。
Tip:压缩图片
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
如果图片像素过大,使用BitmapFactory类的方法实例化Bitmap的过程中,就会发生OutOfMemory异常。
使用BitmapFactory.Options设置inSampleSize就可以缩小图片。属性值inSampleSize表示缩略图大小为原始图片大小的几分之一。即如果这个值为2,则取出的缩略图的宽和高都是原始图片的1/2,图片的大小就为原始大小的1/4。
如果知道图片的像素过大,就可以对其进行缩小。那么如何才知道图片过大呢?
使用BitmapFactory.Options设置inJustDecodeBounds为true后,再使用decodeFile()等方法,并不会真正的分配空间,即解码出来的Bitmap为null,但是可计算出原始图片的宽度和高度,即options.outWidth和options.outHeight。通过这两个值,就可以知道图片是否过大了。

先获取图片真实的宽度和高度,然后判断是否需要跑缩小。如果不需要缩小,设置inSampleSize的值为1。如果需要缩小,则动态计算并设置inSampleSize的值,对图片进行缩小。
Tip:及时回收Bitmap的内存 (≤Android 2.3.3,API10)

Bitmap类的构造方法都是私有的,所以开发者不能直接new出一个Bitmap对象,只能通过BitmapFactory类的各种静态方法来实例化一个Bitmap。
仔细查看BitmapFactory的源代码可以看到,生成Bitmap对象最终都是通过JNI调用方式实现的。所以,加载Bitmap到内存里以后,是包含两部分内存区域的。简单的说,一部分是Java部分的,一部分是C部分的。这个Bitmap对象是由Java部分分配的,不用的时候系统就会自动回收了,但是那个对应的C可用的内存区域,虚拟机是不能直接回收的,这个只能调用底层的功能释放。所以需要调用recycle()方法来释放C部分的内存。从Bitmap类的源代码也可以看到,recycle()方法里也的确是调用了JNI方法了的。
2.3 ListView
Tip:从ContentView获取缓存的view

如果不使用缓存convertView的话,调用getView时每次都会重新创建View,这样之前的View可能还没有销毁,加之不断的新建View势必会造成内存泄露。
Tip:使用ViewHolder模式来避免没有必要的调用findViewById()

ViewHolder模式通过getView()方法返回的视图的标签(Tag)中存储一个数据结构,这个数据结构包含了指向我们要绑定数据的视图的引用,从而避免每次调用getView()的时候调用findViewById()。
2.4 SoftReference & WeakReference

软引用

只有当内存空间不足了,才会回收这些对象的内存。

软引用可用来实现内存敏感的高速缓存。

Map<String, SoftReference<Bitmap>> imageCache = new HashMap<String, SoftReference<Bitmap>>();
弱引用

被垃圾回收器扫描到后即被回收。

Map<String,WeakReference<Bitmap>> cacheMap = new HashMap<String, WeakReference<Bitmap>>();

只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有 弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对 象。

案例:异步加载网络图片

详见:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2013/0920/1554.html
2.5 UI
Tip 1:利用系统资源
系统定义的id:如@android:id/list
系统的图片资源:如@*android:drawable/ic_menu_attachment
系统的文字串资源:如@android:string/yes
系统的Style:如android:textAppearance="?android:attr/textAppearanceMedium“
系统的颜色定义:如android:background ="@android:color/transparent"

说明:
Android系统本身有很多的资源,包括各种各样的字符串、图片、动画、样式和布局等等,这些都可以在应用程序中直接使用。这样做的好处很多,既可以减少内存的使用,又可以减少部分工作量,也可以缩减程序安装包的大小。
Android中没有公开的资源,在xml中直接引用会报错。除了去找到对应资源并拷贝到我们自己的应用目录下使用以外,我们还可以将引用“@android”改成“@*android”解决。
Tip 2:通用模块抽离
<include layout="@layout/navigator_bar" />
背景
头部标题栏
底部导航栏
ListView
Tip 3:ViewStub
ViewStub是一个隐藏的,不占用内存空间的视图对象,它可以在运行时延迟加载布局资源文件。

热心网友 时间:2022-05-14 14:19

Android开发内存优化方式:
1、图片的优化:通常在Android平台中2维图像处理库BitmapFactory做的比较智能,为了减少文件体积和效率,常常不用很多资源文件,而把很多小图片放在一个图片中,有切片的方式来完成,在J2ME中这样是为了将少文件头而解决MIDP这些设备的问题,而Android中虽然机型硬件配置都比较高,有关Android G1硬件配置可以参考G1手机参数以及评测,但是当资源多时这样的运行效率还是令人满意的,至少Dalvik优化的还不是很够。
2、Java内存控制:针对字符串操作而言如果需要连加这样的操作建议使用StringBuilder,经过调试不难发现如果字符串每次连加,使用String需要的内存开销会远大于StringBuilder,然后Android手机常规的运行内存大约在128MB左右,对于运行多任务就需要考虑了,Android开发网提示因为Java有GC不需要手动释放那么分配的时候就要格外的小心,频繁的GC操作仍然是很影响性能的,在调试时可以通过logcat查看内存释放情况。
3、循环使用:一般在访问一个属性的时候效率远比一个固定变量低,如果循环估计次数常常大于5,假设xxx.GetLength()方法的值一般大于5,推荐这样写,比如 for(int i=0;i<xxx.GetLength();i++) 这里xxx.GetLength在每次循环都要调用,必然会影响程序效率,在游戏开发中显得更为明显,改进的方法应该为 int j=xxx.GetLength() for(int i=0;i<j;i++)

热心网友 时间:2022-05-14 15:54

  我的做法是时间换空间,尽量文件化一些占用内存的数据。最典型的就是ListView中的Bitmap,可以参考这个开源组件的实现。 其将Bitmap都本地文件缓存,内存中只保留最近使用的4张图片,在使用中发现还是会偶尔出现OOM,然后我就将其改为完全的读取文件,内存中不保留图片,使用以后都自动回收,由此扩展的数据文件也同样缓存成文件。

  除了Bitmap,其他的地方没想到什么能占用这么大内存,网络下载下来的数据文件?需要都留在内存中吗?目前我做的应用,每次请求的数据大小都比较小,每次Http请求下来的数据都把url转换成文件名,然后缓存成文件,在下次Http请求的时候先根据url来预读文件,暂时不用的数据就释放掉。

  经常会OOM我觉得就是在Bitmap处理的时候,比如decodeFile,在往界面上加载图片时,不用直接加载原图,可以进行缩放。一张1000*1000的图片要加载到一个100*100的ImageView上,直接加载进来大多数都会OOM,可以先用inJustDecodeBounds
  BitmapFactory.Options options = new BitmapFactory.Options();
  options.inJustDecodeBounds = true;
  拿到这个图片的大小,再算好缩放比例
  int scale = 0;
  scale = (int)(options.outHeight / (float)size);
  if (scale <= 0) {
  scale = 1;
  }
  options.inSampleSize = scale;
  options.inJustDecodeBounds = false;
  再进行decode。

  总之就是尽量时间换空间,实际这个时间是非常非常短的,用户体验内的。

热心网友 时间:2022-05-14 17:45

为数据加载设置*缓存。etg:将加载的数据(图片等)存入RAM(如:HashMap)中,并存入本地内存。当用户开启需要加载的界面使,先从RAM获取数据,如果RAM没有,则访问本地获取,若本地有则将本地数据存入RAM再重新执行从RAM获取数据,若本地没有,则访问服务器获取数据,同理传递数据到RAM让数据显示出来。
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
企业培训学到了什么 培训感悟简短 有关培训的感悟 通过培训学到什么 培训你学到了什么 领导问培训学到什么怎么回复 Linux系统安装FTP服务器 Linux系统的网络文件共享 建筑的七盏明灯的内容简介 面向对象设计七大原则 简单说 交互设计七大定律 怎么防止imagecreatefromjpeg内存溢出 关于android里的 recycle()解释 Java如何读取文件夹中所有图片,并显示出来 android,程序中如何改变ImageView大小 如何自动创建自解压格式压缩文件 recycleview怎么使用 android怎么压缩一个bitmap占用空间大小 android 图片占用内存大小怎么计算 电脑进水怎么办 电脑主机装风扇是风对里面吹好?还是把主机里面热吸出来好? 笔记本电脑进水了,吹风扇吹了一天一夜了。可以拿到太阳底下晒吗?求 电脑里的风扇正面是往里吸风还是往外排风? 电脑主机的电源风扇的风是吹进去还是吹出来的呀? 电脑散热的风扇是把外面的空气吸进来还是排出去,严重迷惑中。。 电脑机箱风扇是往里吹还是往外吸的好? 高速强制办理ETC,不办理就不让上高速,这样做你能接受吗? 电脑机箱风扇往外吹还是往里吸比较好( CPU在机箱中间 )? 男子未办ETC收费员不让上高速,为何如此霸气? 电脑主机底部的电源风扇风扇朝下,然后是要吸气进去还是排气出来? 高速兔费时没办ETC是否都可通行? winrar.是压缩软件?可我不会用?怎么用? 有人知道怎么解决安卓模拟器的内存溢出问题吗 Android图片太多,而出异常,哪位高手给解决一下啊? android 如何重写imageview 让图片有圆角效果 肉酱时蔬米线的做法,肉酱时蔬米线怎么做好吃 蔬菜米线的做法步骤图,蔬菜米线怎么做好吃 win7窗口预览怎么设置 在家做米线放什么蔬菜 关闭Win7中的任务栏窗口预览功能 上海话叫米线的蔬菜怎么做好吃? W7怎么设置预览窗口 重庆的三鲜米线是怎么做的哦? win7系统任务栏预览不能显示所有的窗口 win7任务栏窗口预览功能没了 三鲜米线是哪三鲜 android studio 怎么检查内存溢出 win7窗口没有预览图是什么情况? 煮三鲜米线有那些蔬菜? android 怎样释放ImageView中的图片 如何制作u盘启动盘安装xp系统