安卓从图库选择图片时显示内存错误

6

我正在处理一份代码样例,在这份代码中,我需要从图库选择一张图片,虽然代码能够正常工作,但是在从图库选择图片后,我会在OnActivityResult中遇到OutOfMemoryError错误。

我可以获得小图片,但是大图片会出现问题。

下面是我的代码:

try{
                    Uri selectedImageUri = data.getData();
                    String[] filePathColumn = {MediaStore.Images.Media.DATA};
                    Cursor cursor = getContentResolver().query(selectedImageUri, filePathColumn, null, null, null);
                    cursor.moveToFirst();
                    int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                    String filePath = cursor.getString(columnIndex);
                    cursor.close();
                    bitmap = BitmapFactory.decodeFile(filePath);
                    _profileImage.setImageBitmap(bitmap);
                    _profileImage.setScaleType(ScaleType.FIT_XY);
                    Constant._addPhotoBitmap=bitmap;
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    Bitmap resizedbitmap = Bitmap.createScaledBitmap(bitmap, 200, 200, true);
                    resizedbitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
                    byte [] _byteArray = baos.toByteArray();
                    String base64 = Base64.encodeToString(_byteArray,Base64.DEFAULT);
                    Constant._addPhotoBase64 = base64;
                }catch (OutOfMemoryError e) {
                    e.printStackTrace();
                    Constant.showAlertDialog(Constant.errorTitle,
                            "Image size is too large.Please upload small image.",
                            DriverProfileScreen.this, false);
                }   catch (Exception e) {
                    e.printStackTrace();
                }
6个回答

10

您目前是根据文件的 URI 路径直接进行解码,这就是为什么它会抛出异常。在加载图像之前设置一些选项可以减少图像加载时的内存消耗。使用此方法可以加载任意大小的图像。

/**
 * returns the thumbnail image bitmap from the given url
 * 
 * @param path
 * @param thumbnailSize
 * @return
 */
private Bitmap getThumbnailBitmap(final String path, final int thumbnailSize) {
    Bitmap bitmap;
    BitmapFactory.Options bounds = new BitmapFactory.Options();
    bounds.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(path, bounds);
    if ((bounds.outWidth == -1) || (bounds.outHeight == -1)) {
        bitmap = null;
    }
    int originalSize = (bounds.outHeight > bounds.outWidth) ? bounds.outHeight
            : bounds.outWidth;
    BitmapFactory.Options opts = new BitmapFactory.Options();
    opts.inSampleSize = originalSize / thumbnailSize;
    bitmap = BitmapFactory.decodeFile(path, opts);
    return bitmap;
}

2

0

我使用了以下代码,并使用位图将调整大小的图像存储在本地存储中,它非常有效。

final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = 8;

        Bitmap b = BitmapFactory.decodeFile(path, options);

这里的路径是图像的Uri路径在String中。


0

尝试这段代码:

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.app.ActivityManager;
import android.content.ComponentCallbacks;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.support.v4.util.LruCache;
import android.widget.ImageView;

public class UserImageLoaderWithCache implements ComponentCallbacks {
private KCLruCache cache;

public UserImageLoaderWithCache(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
int memoryClass = am.getMemoryClass() * 1024 * 1024;
cache = new KCLruCache(memoryClass);
}

public void display(String url, ImageView imageview, int defaultresource) {
imageview.setImageResource(defaultresource);
Bitmap image = cache.get(url);
if (image != null) {
imageview.setImageBitmap(image);
}
else {
new SetImageTask(imageview).execute(url);
}
}

private class KCLruCache extends LruCache<String, Bitmap> {

public KCLruCache(int maxSize) {
super(maxSize);
}
}

private class SetImageTask extends AsyncTask<String, Void, Integer> {
private ImageView imageview;
private Bitmap bmp;

public SetImageTask(ImageView imageview) {
this.imageview = imageview;
}

@Override
protected Integer doInBackground(String... params) {
String url = params[0];
try {
bmp = getBitmapFromURL(url);
if (bmp != null) {
cache.put(url, bmp);
} else {
return 0;
}
} catch (Exception e) {
e.printStackTrace();
return 0;
} catch (OutOfMemoryError o) {
o.printStackTrace();
return 0;
}
return 1;
}

@Override
protected void onPostExecute(Integer result) {
if (result == 1) {
imageview.setImageBitmap(bmp);
}
super.onPostExecute(result);
}

private Bitmap getBitmapFromURL(String src) {
try {
URL url = new URL(src);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
return myBitmap;
} catch (Exception e) {
e.printStackTrace();
return null;
}catch (OutOfMemoryError o) {
o.printStackTrace();
return null;
}
}
}

public void onLowMemory() {
}

/*public void onTrimMemory(int level) {
if (level >= TRIM_MEMORY_MODERATE) {
cache.evictAll();
}
else if (level >= TRIM_MEMORY_BACKGROUND) {
cache.trimToSize(cache.size() / 2);
}
}*/

public void onConfigurationChanged(Configuration arg0) {
// TODO Auto-generated method stub

}
}

0
先将位图进行缩放,然后再加载它。这样就能解决问题了。
你可以使用以下方法来实现。
private Bitmap getScaledBitmap(Uri uri){
        Bitmap thumb = null ;
        try {
            ContentResolver cr = getContentResolver();
            InputStream in = cr.openInputStream(uri);
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inSampleSize=8;
            thumb = BitmapFactory.decodeStream(in,null,options);
        } catch (FileNotFoundException e) {
            Toast.makeText(PhotoTake.this , "File not found" , Toast.LENGTH_SHORT).show();
        }
        return thumb ; 
    }

希望能有所帮助。


0

通常情况下,Android设备的堆大小仅为16MB(视设备/操作系统而异,详见帖子Heap Sizes)。如果您正在加载图像并且其大小超过16MB,则会引发内存不足异常。与其使用Bitmap来加载图像,不如尝试使用getImageUri从SD卡、资源甚至网络中加载图像。加载位图需要更多的内存,或者如果您完成了对该位图的工作,可以将位图设置为null。

因此,您需要使用以下代码缩小图像:

public static Bitmap decodeFile(File f,int WIDTH,int HIGHT){
 try {
     //Decode image size
     BitmapFactory.Options o = new BitmapFactory.Options();
     o.inJustDecodeBounds = true;
     BitmapFactory.decodeStream(new FileInputStream(f),null,o);
     //The new size we want to scale to
     final int REQUIRED_WIDTH=WIDTH;
     final int REQUIRED_HIGHT=HIGHT;
     //Find the correct scale value. It should be the power of 2.
     int scale=1;
     while(o.outWidth/scale/2>=REQUIRED_WIDTH && o.outHeight/scale/2>=REQUIRED_HIGHT)
         scale*=2;
     //Decode with inSampleSize
     BitmapFactory.Options o2 = new BitmapFactory.Options();
     o2.inSampleSize=scale;
     return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
 } catch (FileNotFoundException e) {}
 return null;
 }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接