那时候只是简单地缓存图片到本地 然后将图片进行压缩,但是感觉这个问题没有很好的解决办法,只是减小了发生的几率
这里,我将前辈们解决的方法重新整理一番,方便自己以后使用。
1.在内存引用上做些处理,常用的有软引用、强化引用、弱引用
01.import
java.lang.ref.PhantomReference;
02.
import
java.lang.ref.Reference;
03.
import
java.lang.ref.ReferenceQueue;
04.
import
java.lang.reflect.Field;
05.
public
class
Test {
06.
public
static
boolean
isRun =
true
;
07.
public
static
void
main(String[] args)
throws
Exception {
08.
String abc =
new
String(
"abc"
);
09.
System.out.println(abc.getClass() +
"@"
+ abc.hashCode());
10.
11.
final
ReferenceQueue referenceQueue =
new
ReferenceQueue<String>();
12.
new
Thread() {
13.
public
void
run() {
14.
while
(isRun) {
15.
Object o = referenceQueue.poll();
16.
if
(o !=
null
) {
17.
try
{
18.
Field rereferent = Reference.
class
19.
.getDeclaredField(
"referent"
);
20.
rereferent.setAccessible(
true
);
21.
Object result = rereferent.get(o);
22.
System.out.println(
"gc will collect:"
23.
+ result.getClass() +
"@"
24.
+ result.hashCode());
25.
}
catch
(Exception e) {
26.
e.printStackTrace();
27.
}
28.
}
29.
}
30.
}
31.
}.start();
32.
PhantomReference<String> abcWeakRef =
new
PhantomReference<String>(abc,
33.
referenceQueue);
34.
abc =
null
;
35.
Thread.currentThread().sleep(
3000
);
36.
System.gc();
37.
Thread.currentThread().sleep(
3000
);
38.
isRun =
false
;
39.
}
40.
}
结果:
class java.lang.String@96354
gc will collect:class java.lang.String@96354
2.在内存中加载图片时直接在内存中做处理
A.边界压缩
01.@SuppressWarnings
(
"unused"
)
02.
private
Bitmap copressImage(String imgPath){
03.
File picture =
new
File(imgPath);
04.
Options bitmapFactoryOptions =
new
BitmapFactory.Options();
05.
//下面这个设置是将图片边界不可调节变为可调节
06.
bitmapFactoryOptions.inJustDecodeBounds =
true
;
07.
bitmapFactoryOptions.inSampleSize =
2
;
08.
int
outWidth = bitmapFactoryOptions.outWidth;
09.
int
outHeight = bitmapFactoryOptions.outHeight;
10.
bmap = BitmapFactory.decodeFile(picture.getAbsolutePath(),
11.
bitmapFactoryOptions);
12.
float
imagew =
150
;
13.
float
imageh =
150
;
14.
int
yRatio = (
int
) Math.ceil(bitmapFactoryOptions.outHeight
15.
/ imageh);
16.
int
xRatio = (
int
) Math
17.
.ceil(bitmapFactoryOptions.outWidth / imagew);
18.
if
(yRatio >
1
|| xRatio >
1
) {
19.
if
(yRatio > xRatio) {
20.
bitmapFactoryOptions.inSampleSize = yRatio;
21.
}
else
{
22.
bitmapFactoryOptions.inSampleSize = xRatio;
23.
}
24.
25.
}
26.
bitmapFactoryOptions.inJustDecodeBounds =
false
;
//false --- allowing the caller to query the bitmap without having to allocate the memory for its pixels.
27.
bmap = BitmapFactory.decodeFile(picture.getAbsolutePath(),
28.
bitmapFactoryOptions);
29.
if
(bmap !=
null
){
30.
//ivwCouponImage.setImageBitmap(bmap);
31.
return
bmap;
32.
}
33.
return
null
;
34.
}
B.边界压缩的情况下间接的使用了软引用来避免OOM
01.
/* 自定义Adapter中部分代码*/
02.
public
View getView(
int
position, View convertView, ViewGroup parent) {
03.
File file =
new
File(it.get(position));
04.
SoftReference<Bitmap> srf = imageCache.get(file.getName());
05.
Bitmap bit = srf.get();
06.
ImageView i =
new
ImageView(mContext);
07.
i.setImageBitmap(bit);
08.
i.setScaleType(ImageView.ScaleType.FIT_XY);
09.
i.setLayoutParams(
new
Gallery.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,
10.
WindowManager.LayoutParams.WRAP_CONTENT));
11.
return
i;
12.
}
但大家都知道,这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存,如果图片多且大,这种方式还是会引用OOM异常的,因此需要进一步处理:
A.第一种方式
01.
InputStream is =
this
.getResources().openRawResource(R.drawable.pic1);
02.
BitmapFactory.Options options=
new
BitmapFactory.Options();
03.
options.inJustDecodeBounds =
false
;
04.
options.inSampleSize =
10
;
//width,hight设为原来的十分一
05.
Bitmap btp =BitmapFactory.decodeStream(is,
null
,options);
06.
if
(!bmp.isRecycle() ){
07.
bmp.recycle()
//回收图片所占的内存
08.
system.gc()
//提醒系统及时回收
09.
}
B.第二中方式
01.
/**
02.
* 以最省内存的方式读取本地资源的图片
03.
* */
04.
public
static
Bitmap readBitMap(Context context,
int
resId){
05.
BitmapFactory.Options opt =
new
BitmapFactory.Options();
06.
opt.inPreferredConfig = Bitmap.Config.RGB_565;
07.
opt.inPurgeable =
true
;
08.
opt.inInputShareable =
true
;
09.
//获取资源图片
10.
InputStream is = context.getResources().openRawResource(resId);
11.
return
BitmapFactory.decodeStream(is,
null
,opt);
12.
}
C.在适当的时候垃圾回收
1.
if
(bitmapObject.isRecycled()==
false
)
//如果没有回收
2.
bitmapObject.recycle();
D.优化Dalvik虚拟机的堆内存分配
对于Android平台来说,其托管层使用的Dalvik JavaVM从目前的表现来看还有很多地方可以优化处理,eg我们在开发一些大型游戏或耗资源的应用中可能考虑手动干涉GC处理,使用 dalvik.system.VMRuntime类提供的setTargetHeapUtilization方法可以增强程序堆内存的处理效率。
1.
private
final
static
floatTARGET_HEAP_UTILIZATION =
0
.75f;
2.
//在程序onCreate时就可以调用
3.
VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION);
4.
即可
至于上面为何是0.75,是因为堆(HEAP)是VM中占用内存最多的部分,通常是动态分配的。堆的大小不是一成不变的,通常有一个分配机制来控制它的大小。比如初始的HEAP是4M大,当4M的空间被占用超过75%的时候,重新分配堆为8M大;当8M被占用超过75%,分配堆为16M大。倒过来,当16M的堆利用不足30%的时候,缩减它的大小为8M大。重新设置堆的大小,尤其是压缩,一般会涉及到内存的拷贝,所以变更堆的大小对效率有不良影响。
E.自定义我们的应用需要多大的内存
1.
private
final
static
int
CWJ_HEAP_SIZE = 6* 1024* 1024 ;
2.
//设置最小heap内存为6MB大小
3.
VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE);
以上这些就是本人总结的一些解决OOM异常的方法,希望能帮助到大家!