加载sd卡上的大图片到内存

处理大图片(图片尺寸比屏幕尺寸大)加载到内存:
当图片太大的时候,直接加载到内存会出现内存溢出的异常
安卓描述图片的原理:0xff ff ff ff: 代表透明度加RGB,也就是32位的二进制数,所以一个int类型的值可以表示一个像素点
假设一个图片的尺寸为:1280*768,说明这个图片要显示出来
需要有(1280*768)个像素点    这里需要注意图片的保存格式,不同格式的图片像素点与byte之间的关系不同
需要(1280*768*4)个字节    因为一个字节等于8位二进制数 单位为B
需要(1280*768*4/1024)    单位为KB

//功能:点击按钮将保存在SD卡的大尺寸的图片加载显示出来
public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        setContentView(R.layout.activity_main);
        Button loadIv=(Button) findViewById(R.id.loadIv);
        final ImageView iv1=(ImageView) findViewById(R.id.iv1);
        loadIv.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                //位图加载到内存是相当消耗资源的,资源是由图片的分辨率(尺寸)决定的,不是由图片的大小决定的,一般的安卓机每个应用只能申请16兆的空间
                //Bitmap bitmap = BitmapFactory.decodeFile("/mnt/sdcard/a.png");
                //iv1.setImageBitmap(bitmap);//直接加载图片显示出来可能会保内存溢出异常,所以需要对图片进行处理
                
                //1.得到手机屏幕的宽和高
                WindowManager wm = getWindowManager();
                //wm.getDefaultDisplay().getWidth();过时的
                Point outSize=new Point();
                wm.getDefaultDisplay().getSize(outSize);
                int screenWidth=outSize.x;//屏幕的宽度
                int screenHeight=outSize.y;//手机屏幕的高度
                System.out.println("手机屏幕的X轴:"+screenWidth+"---Y轴:"+screenHeight);
                //2.得到图片的宽高(不解析位图,只是获取图片的图片信息)
                Options opts=new Options();//解析位图的附加条件
                opts.inJustDecodeBounds=true;//如果设置为true,表示只是获取图片的图片信息而不去解析(注意这样返回的bitmap为null)
                Bitmap bitmap=BitmapFactory.decodeFile(Environment.getExternalStorageDirectory().getPath()+"/a.png", opts);
                int bitmapWidth=opts.outWidth;//得到图片的宽度
                int bitmapHeight=opts.outHeight;//不能使用bitmap.getWidth();因为bitmap为空
                System.out.println("图片的宽:"+bitmapWidth+"---高:"+bitmapHeight);
                //3.处理图片的缩放比例
                int dx=bitmapWidth/screenWidth;//X轴的缩放比例
                int dy=bitmapHeight/screenHeight;//Y轴的缩放比例
                int scale=1;//记录缩放比例
                //为了使屏幕能够装下图片,需要选择缩放比大的那个
                if(dx>dy && dy>=1){//图片的尺寸必须大于屏幕的尺寸才缩放
                    System.out.println("按照水平方向缩放,缩放比例为:"+dx);
                    scale=dx;
                }else if(dy>dx && dx>=1){
                    System.out.println("按照垂直方向缩放,缩放比例为:"+dy);
                    scale=dy;
                }
                //4.执行对图片的处理,加载图片到内存
                opts.inSampleSize=scale;//如果设置的值>1,表示请求解码器子样品原始图像,返回一个较小的图像以节省内存
                opts.inJustDecodeBounds=false;//表示需要解析图片(需要显示)
                bitmap=BitmapFactory.decodeFile(Environment.getExternalStorageDirectory().getPath()+"/a.png", opts);
                iv1.setImageBitmap(bitmap);//显示图片
            }
        });
    }
}

因此在展示高分辨率图片的时候,最好先将图片进行压缩。压缩后的图片大小应该和用来展示它的控件大小相近,在一个很小的ImageView上显示一张超大的图片不会带来任何视觉上的好处,但却会占用我们相当多宝贵的内存,而且在性能上还可能会带来负面影响。下面我们就来看一看,如何对一张大图片进行适当的压缩,让它能够以最佳大小显示的同时,还能防止OOM的出现。

BitmapFactory这个类提供了多个解析方法(decodeByteArray, decodeFile, decodeResource等)用于创建Bitmap对象,我们应该根据图片的来源选择合适的方法。比如SD卡中的图片可以使用decodeFile方法,网络上的图片可以使用decodeStream方法,资源文件中的图片可以使用decodeResource方法。这些方法会尝试为已经构建的bitmap分配内存,这时就会很容易导致OOM出现。为此每一种解析方法都提供了一个可选的BitmapFactory.Options参数,将这个参数的inJustDecodeBounds属性设置为true就可以让解析方法禁止为bitmap分配内存,返回值也不再是一个Bitmap对象,而是null。虽然Bitmap是null了,但是BitmapFactory.Options的outWidth、outHeight和outMimeType属性都会被赋值。这个技巧让我们可以在加载图片之前就获取到图片的长宽值和MIME类型

 我们可以通过下面的代码看出每个应用程序最高可用内存是多少。

int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
Log.d("TAG", "Max memory is " + maxMemory + "KB");

 具体使用见: 磁盘缓存-DiskLruCache

posted @ 2016-06-01 16:32  ts-android  阅读(420)  评论(0编辑  收藏  举报