createBitmap

时间:2017-01-27 14:07:19

标签: android image bitmap out-of-memory

您好我正在创建图像编辑应用程序我是否为canvas和imageview创建位图

这里我在imageView中使用 385kb 图像文件 2000x2000 维度

这是图片enter image description here

我的问题是,我第一次使用其他小图像和编辑图像创建位图时,它会工作一段时间,但是第二次使用上面的尺寸和尺寸,它会生成java.lang.OutOfMemoryError :(

这是我的相关方法代码

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // initialize variable
        init();

        // initialize view
        initView();

        // initialize view's event listener
        initEventListener();

        setImageToImageView(ims);

    }  

private void init() {

        context = MainActivity.this;
        db_colorImage = new DB_ColorImage(context);

        AppUtils.setColorPreference(MainActivity.this, AppConstant.PREF_COLOR_PIC, "FF0000");
        AppUtils.setComboColorPreference(MainActivity.this, AppConstant.PREF_COMBO, 1);

        openCatId = getIntent().getIntExtra("open_cat_id", -1);
        openCat = getIntent().getStringExtra("image_categoryname");
        openImgName = getIntent().getStringExtra("img_name");

        db_colorImage.openDB();
        db_colorImage.startTransaction();
        assetsImgxx = db_colorImage.getXXX(openCatId);
        db_colorImage.successfullTransaction();
        db_colorImage.completeTransaction();
        db_colorImage.closeDB();


        assetsAndSdImage = new ArrayList<>(getIntent().getStringArrayListExtra("again"));           // aa list edit karelu with sdcard image

        try {

            ims = getAssets().open(openCat + "/" + openImgName);
        } catch (IOException e) {
            File getFromSd = new File(AppUtils.appFolder() + File.separator + openImgName);
            try {
                ims = new FileInputStream(getFromSd);
            } catch (FileNotFoundException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        }

    }  

    public void setImageToImageView(InputStream ims) {
        Drawable d = Drawable.createFromStream(ims, null);

        BitmapDrawable drawable = (BitmapDrawable) d;

        Bitmap bmp = drawable.getBitmap();


        if (bmp != null) {
            _alteredBitmap = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888); // here i used ARGB_8888 because jnibitmap.cpp also use ARGB_8888. If we do not use this it wont color on image
        }

        Canvas canvas = new Canvas(_alteredBitmap);

        Paint paint = new Paint();

        Matrix matrix = new Matrix();

        canvas.drawBitmap(bmp, matrix, paint);

        imageView.setImageBitmap(_alteredBitmap);  // we can also use imageView.setImageResource(R.drawable.test_image);

        // ******* clear bitmap after use *******
        // check after done this step it will not produce any problem
        if (bmp != null) {
            bmp.recycle();
            bmp = null;
        }
    }  
  

_alteredBitmap = Bitmap.createBitmap(bmp.getWidth(),bmp.getHeight(),Bitmap.Config.ARGB_8888);

在这行我获得EXCEPTION,这是日志

01-27 19:12:33.590 27252-27252/? E/AndroidRuntime: FATAL EXCEPTION: main
                                                   java.lang.OutOfMemoryError
                                                       at android.graphics.Bitmap.nativeCreate(Native Method)
                                                       at android.graphics.Bitmap.createBitmap(Bitmap.java:640)
                                                       at android.graphics.Bitmap.createBitmap(Bitmap.java:620)
                                                       at com.yptech.myfloodfilldemo.ui.MainActivity.setImageToImageView(MainActivity.java:387)
                                                       at com.yptech.myfloodfilldemo.ui.MainActivity.onCreate(MainActivity.java:96)
                                                       at android.app.Activity.performCreate(Activity.java:5008)
                                                       at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
                                                       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
                                                       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
                                                       at android.app.ActivityThread.access$600(ActivityThread.java:130)
                                                       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
                                                       at android.os.Handler.dispatchMessage(Handler.java:99)
                                                       at android.os.Looper.loop(Looper.java:137)
                                                       at android.app.ActivityThread.main(ActivityThread.java:4745)
                                                       at java.lang.reflect.Method.invokeNative(Native Method)
                                                       at java.lang.reflect.Method.invoke(Method.java:511)
                                                       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
                                                       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
                                                       at dalvik.system.NativeStart.main(Native Method)  

编辑图像后,我保存此图像,因此我不想降低图像质量,因此我使用 Bitmap.Config.ARGB_8888 。我在位图上尝试了很多像android developer document这样的解决方案,但它对我不起作用。

是OutOfMemoryError取决于图像大小和尺寸???以及如何在createBitmap ??

时解决OutOfMemoryError的问题

当我使用largHeap它工作正常但是更好的方法使用 android:largeHeap =&#34; true&#34; ??

提前感谢:)

4 个答案:

答案 0 :(得分:2)

在使用之前优化位图。

Bitmap bitmap = MediaOptimize.reduceResolution(mediaPath, width, height);

功能:

public Bitmap reduceResolution(String filePath, int viewWidth, int viewHeight) {
    int reqHeight = viewHeight;
    int reqWidth = viewWidth;

    BitmapFactory.Options options = new BitmapFactory.Options();

    // First decode with inJustDecodeBounds=true to check dimensions
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(filePath, options);

    double viewAspectRatio = 1.0 * viewWidth/viewHeight;
    double bitmapAspectRatio = 1.0 * options.outWidth/options.outHeight;

    if (bitmapAspectRatio > viewAspectRatio)
        reqHeight = (int) (viewWidth/bitmapAspectRatio);
    else
        reqWidth = (int) (viewHeight * bitmapAspectRatio);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    System.gc();                                        // TODO - remove explicit gc calls
    return BitmapFactory.decodeFile(filePath, options);
}


private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {

    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {
        // Calculate ratios of height and width to requested height and width
        final int heightRatio = Math.round((float) height / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);

        // Choose the smallest ratio as inSampleSize value, this will guarantee
        // a final image with both dimensions larger than or equal to the
        // requested height and width.
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    }
    return inSampleSize;
}

答案 1 :(得分:1)

我正在使用Glide(https://bumptech.github.io/glide/)有效地加载大型位图。如果要从设备加载照片,Glide还会为您处理正确的旋转。

val myUri = ...
val neededHeight = 600
val neededWidth = 800

val bitmap = GlideApp
                .with(context)
                .asBitmap()
                .load(myUri)
                .override(neededWidth, neededHeight)
                .submit()
                .get()

答案 2 :(得分:0)

试试这个,只需将其添加到AndroidManifest.xml

即可
<application
    ...
    android:largeHeap="true">
    <activity
        android:name=".MainActivity"
        ...

答案 3 :(得分:-1)

图像很大。我建议缩小图像或使用毕加索库来更好地利用内存问题和图像缓存。