Bitmap太多使用LrcCache 或者 软引用 来解决
对于图片太大的问题,展现给用户的是通过inSample压缩过的。File--->压缩过的Bitmap
而上传到服务器的File-->inputStream---->Byte[]----->Base64编码传输
如果直接File--->原始的没有压缩的大Bitmap--->Byte[] ----->Base64编码传输 这样会造成内存溢出
难道第一个不会溢出吗?
android中Bitmap是经常需要用到的,并且Bitmap对象占用了一部分虚拟机内存和一部分C内存,所以使用的使用需要注意一些问题,避免出现OOM问题。OOM除了内存泄露之外,
图片过大或者图片过多都会导致OOM,对于图片过多可以使用LrcCache或者软引用的方式来解决。对于过大的图片需要在上传、下载、显示的时候注意降低内存的占用。
下面以“拍摄身份证后台上传,下载显示”的场景为例。
1.由于拍摄的照片很大,并且上传的时候要上传拍摄的原始图片,所以拍照的时候需要指定照片的生成路径,后台完成磁盘原始图片的上传。
(注意不要通过Bundle传递拍照的生成的Bitmap,那样图片失真很大)
/** * 拍照intent * @param requestCode * @return 生成图片的路径 * */ public static String startTakePhotoIntent(Activity context,int requestCode){ Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); String path = Environment.getExternalStorageMiuiDirectory().getAbsolutePath() + System.currentTimeMillis() + ".jpg"; intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(path))); intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); context.startActivityForResult(intent,requestCode); return path; } /** * 拍照intent * @param requestCode * @return 生成图片的路径 * */ protected class UploadBitmapThread extends Thread{ String path; public UploadBitmapThread(String p,String t,Bitmap b){ path = p; } @Override public void run(){ File file = new File(path); byte[] fileBytes = Utilities.getBytesFromFile(file); //上传图片 } } |
2.对于图片的下载,因为ImageView显示的只是某一个小区域,没必要把整个图片完成下载,
/** *通过采样的方法获取图片大小,然后下载等比压缩后的网络图片 */ public static Bitmap decodeBitmap(URL url) { final float DISPLAY_WIDTH = 1000; final float DISPLAY_HEIGHT = 1000;//可以把ImageView的宽高作为参数传入,根据显示区域的大小,决定压缩的比例。 byte[] data = getBytes(inputStream);//输入流转化为数组 InputStream inputStream = url.openStream() BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeByteArray(data, 0, data.length, options); int wRatio = (int) Math.ceil(options.outWidth / DISPLAY_WIDTH);//1920 1080 int hRatio = (int) Math.ceil(options.outHeight / DISPLAY_HEIGHT); // 如果超出指定大小,则缩小相应的比例 if (wRatio > 1 && hRatio > 1) { if (wRatio > hRatio) { options.inSampleSize = wRatio; } else { options.inSampleSize = hRatio; } } options.inJustDecodeBounds = false; //bitmap=BitmapFactory.decodeStream(inputStream,null,options); Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options); return bitmap; } |
3.对于图片的释放是否有必要调用recycle()
只有当你确认你不会在使用这个bitmap的时候,就可以选择调用recycle()方法释放它。该不该使用recycle方法,完全取决于你自己的水平,因为我在自己认为bitmap已经完全不会再使用的地方调用了recycle方法结果在某些条件下还是出现了上面的异常。所以recycle方法虽好,但是你要能够驾驭,而且一般情况下是不需要他的。
下面这种情况就是手动调用recycle()导致异常。
当你根据id从drawable(drawable资源文件夹)中获取一个drawable时,系统会将这个drawable加入缓存之中。这样,你第二次继续获取这个drawable时,如果缓存之中的drawable没有被回收,则会被返回。
如果你通过getDrawable(id)方法获取到一个bitmap1,继续通过getDrawable(id)方法获取到一个bitmap2。那么bitmap1=bitmap2。所以,当你对bitmap1进行recycle之后,又将bitmap2设置给Imageview显示,极大可能会出现java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@xxx的错误。