android 大图无损上传

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的错误。



你可能感兴趣的:(android 大图无损上传)