当我们在做项目过程中,一遇到显示图片时,就要考虑图片的大小,所占内存的大小,原因就是Android分配给Bitmap的大小只有8M,试想想我们用手机拍照,普通的一张照片不也得1M以上,所以android处理图片时不得不考虑图片过大造成的内存异常。

   那时候只是简单地缓存图片到本地 然后将图片进行压缩,但是感觉这个问题没有很好的解决办法,只是减小了发生的几率


    这里,我将前辈们解决的方法重新整理一番,方便自己以后使用。

   1.在内存引用上做些处理,常用的有软引用、强化引用、弱引用(可以参考这篇博客:http://smallwoniu.blog.51cto.com/blog/3911954/1248751)

import java.lang.ref.PhantomReference;import java.lang.ref.Reference;import java.lang.ref.ReferenceQueue;import java.lang.reflect.Field;public class Test {    public static boolean isRun = true;    public static void main(String[] args) throws Exception {        String abc = new String("abc");        System.out.println(abc.getClass() + "@" + abc.hashCode());                                                                                                                                                                                                                                                                                                                                                                                                                       final ReferenceQueue referenceQueue = new ReferenceQueue();        new Thread() {            public void run() {                while (isRun) {                    Object o = referenceQueue.poll();                    if (o != null) {                        try {                            Field rereferent = Reference.class                                    .getDeclaredField("referent");                            rereferent.setAccessible(true);                            Object result = rereferent.get(o);                            System.out.println("gc will collect:"                                    + result.getClass() + "@"                                    + result.hashCode());                        } catch (Exception e) {                            e.printStackTrace();                        }                    }                }            }        }.start();        PhantomReference abcWeakRef = new PhantomReference(abc,                referenceQueue);        abc = null;        Thread.currentThread().sleep(3000);        System.gc();        Thread.currentThread().sleep(3000);        isRun = false;    }}

结果:

class java.lang.String@96354 gc will collect:class java.lang.String@96354

2.在内存中加载图片时直接在内存中做处理

  A.边界压缩

@SuppressWarnings("unused")private Bitmap copressImage(String imgPath){    File picture = new File(imgPath);    Options bitmapFactoryOptions = new BitmapFactory.Options();    //下面这个设置是将图片边界不可调节变为可调节    bitmapFactoryOptions.inJustDecodeBounds = true;    bitmapFactoryOptions.inSampleSize = 2;    int outWidth  = bitmapFactoryOptions.outWidth;    int outHeight = bitmapFactoryOptions.outHeight;    bmap = BitmapFactory.decodeFile(picture.getAbsolutePath(),         bitmapFactoryOptions);    float p_w_picpathw = 150;    float p_w_picpathh = 150;    int yRatio = (int) Math.ceil(bitmapFactoryOptions.outHeight            / p_w_picpathh);    int xRatio = (int) Math            .ceil(bitmapFactoryOptions.outWidth / p_w_picpathw);    if (yRatio > 1 || xRatio > 1) {        if (yRatio > xRatio) {            bitmapFactoryOptions.inSampleSize = yRatio;        } else {            bitmapFactoryOptions.inSampleSize = xRatio;        }                                                                                                                                                                                                                                                       }     bitmapFactoryOptions.inJustDecodeBounds = false;//false --- allowing the caller to query the bitmap without having to allocate the memory for its pixels.    bmap = BitmapFactory.decodeFile(picture.getAbsolutePath(),            bitmapFactoryOptions);    if(bmap != null){                       //ivwCouponImage.setImageBitmap(bmap);        return bmap;    }    return null;}

   B.边界压缩的情况下间接的使用了软引用来避免OOM

/* 自定义Adapter中部分代码*/        public View getView(int position, View convertView, ViewGroup parent) {            File file = new File(it.get(position));            SoftReference srf = p_w_picpathCache.get(file.getName());            Bitmap bit = srf.get();            ImageView i = new ImageView(mContext);            i.setImageBitmap(bit);            i.setScaleType(ImageView.ScaleType.FIT_XY);            i.setLayoutParams( new Gallery.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,                    WindowManager.LayoutParams.WRAP_CONTENT));            return i;        }

 

    但大家都知道,这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存,如果图片多且大,这种方式还是会引用OOM异常的,因此需要进一步处理:

  A.第一种方式

InputStream is = this.getResources().openRawResource(R.drawable.pic1);     BitmapFactory.Options options=new BitmapFactory.Options();     options.inJustDecodeBounds = false;     options.inSampleSize = 10;   //width,hight设为原来的十分一     Bitmap btp =BitmapFactory.decodeStream(is,null,options); if(!bmp.isRecycle() ){         bmp.recycle()   //回收图片所占的内存         system.gc()  //提醒系统及时回收}

 

    B.第二中方式

/*** 以最省内存的方式读取本地资源的图片* */  public static Bitmap readBitMap(Context context, int resId){          BitmapFactory.Options opt = new BitmapFactory.Options();          opt.inPreferredConfig = Bitmap.Config.RGB_565;          opt.inPurgeable = true;         opt.inInputShareable = true;            //获取资源图片         InputStream is = context.getResources().openRawResource(resId);             return BitmapFactory.decodeStream(is,null,opt);     }

   

   C.在适当的时候垃圾回收

if(bitmapObject.isRecycled()==false) //如果没有回收           bitmapObject.recycle();


   D.优化Dalvik虚拟机的堆内存分配

    对于Android平台来说,其托管层使用的Dalvik JavaVM从目前的表现来看还有很多地方可以优化处理,eg我们在开发一些大型游戏或耗资源的应用中可能考虑手动干涉GC处理,使用 dalvik.system.VMRuntime类提供的setTargetHeapUtilization方法可以增强程序堆内存的处理效率。

private final static floatTARGET_HEAP_UTILIZATION = 0.75f; //在程序onCreate时就可以调用VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION);即可

  至于上面为何是0.75,是因为堆(HEAP)是VM中占用内存最多的部分,通常是动态分配的。堆的大小不是一成不变的,通常有一个分配机制来控制它的大小。比如初始的HEAP是4M大,当4M的空间被占用超过75%的时候,重新分配堆为8M大;当8M被占用超过75%,分配堆为16M大。倒过来,当16M的堆利用不足30%的时候,缩减它的大小为8M大。重新设置堆的大小,尤其是压缩,一般会涉及到内存的拷贝,所以变更堆的大小对效率有不良影响。


   E.自定义我们的应用需要多大的内存

private final static int CWJ_HEAP_SIZE = 6* 1024* 1024 ; //设置最小heap内存为6MB大小VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE);


   以上这些就是本人总结的一些解决OOM异常的方法,希望能帮助到大家!


参考博客:http://blog.sina.com.cn/s/blog_7501670601014dcj.html


更多相关文章

  1. Android React Native加载图片资源的正确姿势
  2. Android仿淘宝首页UI(附代源代码及示例图片)
  3. 【Android 内存优化】使用 Memory Analyzer ( MAT ) 工具分析内
  4. 必须得明白Android内存管理,千万别把windows的习惯带过来
  5. Android换肤功能设计与实现(5)——网络加载及图片内存管理
  6. Android OpenGLES2.0(八)——纹理贴图之显示图片
  7. Android处理图片OOM的若干方法小结
  8. android 图片圆角 遮罩_安卓圆角、背景遮罩。覆盖实现方式(适用于
  9. Android 图片资源的异步加载2

随机推荐

  1. Android中微信主界面菜单栏的布局实现代
  2. Android(安卓)Material Design 系列之 Se
  3. Android菜鸟的成长笔记(14)—— Android中
  4. Android群英传笔记——第六章:Android绘图
  5. Android中文翻译组 - 简介
  6. android UI进阶之android中隐藏的layout
  7. 在Android中实现Hook机制的实验
  8. 最封闭的开源系统,话说Android的八宗罪(转
  9. Android应用开发笔记(13): Android移动应
  10. 从0开始学Android之Android生命周期