2016-09-29 4 views
2

У меня возникают проблемы с загрузкой изображения на экран определенных устройств.Ошибка OOM даже при декодировании изображения

Весь экран имеет одно изображение, но его довольно высокое изображение.

Ниже приведены размеры изображения

Портрет:

  • MDPI: 360x1074
  • ИПЧР: 540x1611
  • xhdpi: 720x2148
  • xxhdpi: 1080x3142

пейзаж:

  • MDPI: 640x705
  • ИПЧР: 960x1058
  • xhdpi: 1280x1410
  • xxhdpi: 1920x1035

Я следовал: https://developer.android.com/training/displaying-bitmaps/load-bitmap.html также это http://successmatics.com/blog/loading-large-bitmaps-in-android-ui/, но они в основном то же самое.

Если я загружаю гораздо меньшее изображение, скажем, миниатюру чего-то еще, он загружается нормально.

Загрузка изображения в OnCreate

mImageView.setImageBitmap(
    ImageUtils.decodeSampledBitmapFromResource(getResources(), 
    R.drawable.image, 
    ImageUtils.getScreenWidth(getApplicationContext()), 
    ImageUtils.getScreenHeight(getApplicationContext()))); 
} 

методы, используемые для декодирования изображения (от 2 URLs выше)

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) { 

    // First decode with inJustDecodeBounds=true to check dimensions 
    final BitmapFactory.Options options = new BitmapFactory.Options(); 
    options.inJustDecodeBounds = true; 
    BitmapFactory.decodeResource(res, resId, options); 

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

    // Decode bitmap with inSampleSize set 
    options.inJustDecodeBounds = false; 
    return BitmapFactory.decodeResource(res, resId, options); 
    } 

    public static int calculateInSampleSize(
      BitmapFactory.Options options, int reqWidth, int reqHeight) { 
    // Raw height and width of image 
    final int height = options.outHeight; 
    final int width = options.outWidth; 
    int inSampleSize = 1; 

    if (height > reqHeight || width > reqWidth) { 

     final int halfHeight = height/2; 
     final int halfWidth = width/2; 

     // Calculate the largest inSampleSize value that is a power of 2 and keeps both 
     // height and width larger than the requested height and width. 
     while ((halfHeight/inSampleSize) >= reqHeight 
       && (halfWidth/inSampleSize) >= reqWidth) { 
//--------i tried a sample size of 2. was hoping 3 would work---------// 
     inSampleSize *= 3; 
     } 
    } 

    return inSampleSize; 
    } 

    public static int getScreenWidth(Context context) { 
    DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); 
    return displayMetrics.widthPixels; 
    } 

    public static int getScreenHeight(Context context) { 
    DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); 
    return displayMetrics.heightPixels; 
    } 

Кто-нибудь есть лучший способ декодирования больших изображений, так что я не получаю ООМ

или

есть что-то случилось с моим кодом (бея ч от андроид себя)

EDIT: К сожалению забыл StackTrace:

E/dalvikvm-heap: Out of memory on a 10391232-byte allocation. 
    I/dalvikvm: "main" prio=5 tid=1 RUNNABLE 
    I/dalvikvm: | group="main" sCount=0 dsCount=0 obj=0xb264b450 self=0xb8d604e0 
    I/dalvikvm: | sysTid=26630 nice=0 sched=0/0 cgrp=[fopen-error:2] handle=-1216986048 
    I/dalvikvm: | schedstat=(0 0 0) utm=117 stm=69 core=0 
    I/dalvikvm:  at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method) 
    I/dalvikvm:  at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:500) 
    I/dalvikvm:  at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:353) 
    I/dalvikvm:  at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:781) 
    I/dalvikvm:  at android.content.res.Resources.loadDrawable(Resources.java:1935) 
    I/dalvikvm:  at android.content.res.TypedArray.getDrawable(TypedArray.java:601) 
    I/dalvikvm:  at android.widget.ImageView.<init>(ImageView.java:120) 
    I/dalvikvm:  at android.support.v7.widget.AppCompatImageView.<init>(AppCompatImageView.java:57) 
    I/dalvikvm:  at android.support.v7.widget.AppCompatImageView.<init>(AppCompatImageView.java:53) 
    I/dalvikvm:  at android.support.v7.app.AppCompatViewInflater.createView(AppCompatViewInflater.java:106) 
    I/dalvikvm:  at android.support.v7.app.AppCompatDelegateImplV7.createView(AppCompatDelegateImplV7.java:980) 
    I/dalvikvm:  at android.support.v7.app.AppCompatDelegateImplV7.onCreateView(AppCompatDelegateImplV7.java:1039) 
    I/dalvikvm:  at android.support.v4.view.LayoutInflaterCompatHC$FactoryWrapperHC.onCreateView(LayoutInflaterCompatHC.java:44) 
    I/dalvikvm:  at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:675) 
    I/dalvikvm:  at android.view.LayoutInflater.rInflate(LayoutInflater.java:746) 
    I/dalvikvm:  at android.view.LayoutInflater.rInflate(LayoutInflater.java:749) 
    I/dalvikvm:  at android.view.LayoutInflater.rInflate(LayoutInflater.java:749) 
    I/dalvikvm:  at android.view.LayoutInflater.inflate(LayoutInflater.java:489) 
    I/dalvikvm:  at android.view.LayoutInflater.inflate(LayoutInflater.java:396) 
    I/dalvikvm:  at android.view.LayoutInflater.inflate(LayoutInflater.java:352) 
    I/dalvikvm:  at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:280) 
    I/dalvikvm:  at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:140) 
    I/dalvikvm:  at com.myapp.app.item.protection.Protection.onCreate(Protection.java:31) 
    I/dalvikvm:  at android.app.Activity.performCreate(Activity.java:5008) 
    I/dalvikvm:  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079) 
    I/dalvikvm:  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023) 
    I/dalvikvm:  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084) 
    I/dalvikvm:  at android.app.ActivityThread.access$600(ActivityThread.java:130) 
    I/dalvikvm:  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195) 
    I/dalvikvm:  at android.os.Handler.dispatchMessage(Handler.java:99) 
    I/dalvikvm:  at android.os.Looper.loop(Looper.java:137) 
    I/dalvikvm:  at android.app.ActivityThread.main(ActivityThread.java:4745) 
    I/dalvikvm:  at java.lang.reflect.Method.invokeNative(Native Method) 
    I/dalvikvm:  at java.lang.reflect.Method.invoke(Method.java:511) 
    I/dalvikvm:  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786) 
    I/dalvikvm:  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) 
    I/dalvikvm:  at dalvik.system.NativeStart.main(Native Method) 

только загрузка библиотеки изображений Я использую в настоящее время является Volley для сетевых изображений. Это ресурс в файле @Drawable.Есть 2 версии, портрет и пейзаж (Не хочу протягивать)

Благодаря

+0

Опубликовать свой логарифм ?? Вы используете любую библиотеку для загрузки изображений? – PN10

+0

см. В редакции – x10sion

ответ

0

заменить эту строку

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

с

будет решена проблема

options.inSampleSize = 8; 
+0

, что такие работы, кроме изображения, теперь раздавлены в верхней части активности? – x10sion

+0

Да, потому что inSampleSize возвращает меньшее изображение для сохранения памяти, следовательно, качество будет понижаться вниз –

+0

Есть ли способ показать, что он все еще отображается с одинаковым размером, но при немного более низком качестве? – x10sion

0

вот метод, который я обычно использую для расчета inSampleSize

private int calculateInSampleSize(BitmapFactory.Options opts, int reqWidth, int reqHeight) { 
    int outHeight = opts.outHeight; 
    int outWidth = opts.outWidth; 
    int inSampleSize = 1; 
    while (outHeight > reqHeight || outWidth > reqWidth) { 
     outHeight /= 2; 
     outWidth /= 2; 
     inSampleSize *= 2; 
    } 
    return inSampleSize; 
} 

, если вы хотите, чтобы ваш растровый подходит для вашего ImageView, вы можете использовать scaleType в XML, как:

<ImageView 
    android:scaleType="centerCrop" 
    android:id="@+id/test_iv" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"/> 

Если вы не хотите, чтобы декодировать изображение самостоятельно, вы можете использовать некоторые третья часть библиотеки как Glide

+0

Есть ли способ показать, что он по-прежнему отображается с одинаковым размером, но при немного более низком качестве, потому что мое изображение отключается от экрана в виде его довольно длинного изображения. – x10sion

0

Существует что-то случилось с моим кодом (который от самих андроид )

Неплохо (в некотором смысле это не работает). что он делает, что сказано.

Кто-нибудь есть лучший способ декодирования больших изображений, так что я не получаю ОЫЙ

Ammm .. я нет, но я могу показать вам, где вы можете внести изменения, чтобы сделать эту работу ,

Существует проблема с условием, которое вы использовали для расчета индекса вниз-образца. я объясню это примером, указанным в вашем вопросе.

Configuration landscape 

XXHDPI qhd device with dimention 960x540 hence, 

    deviceWidth 960 deviceHeight 540 
    halfWidth 960 halfHeight 517 
    imgWidth 1920 imgHeight 1035 

Ширина устройства является искомым ширина здесь так,

reqWidth 960 reqHeight 540  

состояние, которое вы использовали в

while ((halfHeight/inSampleSize) >= reqHeight 
       && (halfWidth/inSampleSize) >= reqWidth) { 
//--------i tried a sample size of 2. was hoping 3 would work---------// 
     inSampleSize *= 3; 
     } 

Если мы просто установить параметр становится

while ((517/1) >= 540 
       && (960/1) >= 960) { 
//--------i tried a sample size of 2. was hoping 3 would work---------// 
     inSampleSize *= 3; 
     } 

Как вы видите первый условие не удовлетворяет, поэтому в то время как цикл разбит, а inSampleSize остается 1, значит, изображение не будет повторно отбираться. которые могут вызвать OOM.

Идея заключается в том, как вы идете по направлению к изображениям с более высоким соотношением сторон оно будет больше шансов получить OOM с данным условием,

например , Изображение с размером 2160 x 1035 с большей вероятностью приведет к краху вашего приложения (обратите внимание: это изображение не будет повторно отобрано по той же причине).

И изображение с размерами 4320 х 1035, безусловно, сбою приложения (примечание: это обыкновение повторно образец либо)

и так же 1035 х 4320 (Портрет случай).

Так что же изменить? условие должно быть изменено, чтобы сделать его сделать что-то вроде этого,

Get the large side of image, down sample it until it fits adjacent device side 

я оставлю это до вас, чтобы изменить состояние, как вы можете, кажется нужным.

UPLDATE:

Я хотел бы заявить, что в комментариях OP this ответить в затронул ссылку на суть, которая действительно демонстрирует то, что вы ищете. он также переходит на дополнительную милю, уменьшая размер данного растрового изображения, установив конфигурацию растрового изображения в RGB_565, которая использует 16 бит на пиксель (RGB_888 использует 24).

scaledBitmap = Bitmap.createBitmap(actualWidth, actualHeight, Bitmap.Config.RGB_565); 

Обратите внимание, что это приведет к снижению качества изображения.

+0

Есть ли у вас пример ImageCompression в сущности мне видеть? – x10sion