2017-02-17 34 views
1

Я знаю, что если я загружаю изображение и устанавливаю его как источник в ImageView программно, то лучше всего сначала вычислить размер изображения с помощью inJustDecodeBounds, выяснить, сколько масштабирования мне нужно, а затем декодировать с этим масштабированием:Будет ли Android автоматически использовать inJustDecodeBounds при установке источника ImageView в xml?

BitmapFactory.Options options = new BitmapFactory.Options(); 
options.inJustDecodeBounds = true; 
BitmapFactory.decodeResource(getResources(), R.drawable.my_drawable, options); 

float srcHeight = options.outHeight; 
float srcWidth = options.outWidth; 

int inSampleSize = ...; // compute 

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

Bitmap myBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.my_drawable, options); 

myImageview.setImageBitmap(myBitmap); 

Теперь, если я вместо этого хочу, чтобы установить это в XML , и я только обеспечиваю базовую вытяжку в /drawables (нет других активов в /drawables-hdpi и т.д.)

<ImageView 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:src="@drawable/my_drawable"/> 

Я знаю, что Android сделает какое-то масштабирование полученного растрового изображения, чтобы убедиться, что оно подходит, но будет ли оно делать это эффективно, как если бы я сам расшифровывал растровое изображение? Или он загружает весь битмап в память и , а затем масштабирует его?

Другими словами, когда Android остается на своих устройствах для повторной выборки изображения, когда я предоставляю базу /drawable, она делает это эффективно?

ответ

1

Если вы уверены в том, что вы хотите, масштабирование Bitmap само спасет память, потому что андроид не сделает этого, по крайней мере, не так, как вы могли ожидать (см. Редактирование внизу и комментарии).

Думаю, вам нужно сделать и другое соображение. Когда вы декодируете растровое изображение самостоятельно, вы ориентируетесь на размер, возможно, размер ImageView (поэтому после вычисления размера ImageView). При раздувании xml этот размер пока неизвестен. Что произойдет, если размер ImageView изменится после того, как вы декодировали Bitmap? Вы бы перетащили его? В таком случае не было бы более эффективно декодировать более крупный Bitmap, а затем просто масштабировать чертеж?

Один из способов узнать, масштабируется ли размер файла Bitmap, так как вы бы очень просто, попробуйте установить смехотворно большое изображение как src в xml и посмотреть, что произойдет (предупреждение о спойлере, оно взорвется).

копания в исходный код, кажется, что Bitmap для ГКЗ ImageView декодируется в этом методе Drawable класса, похоже, что он не принимает во внимание размер, но только плотность экрана

public static Drawable createFromResourceStream(Resources res, TypedValue value, 
     InputStream is, String srcName, BitmapFactory.Options opts) { 
    if (is == null) { 
     return null; 
    } 

    /* ugh. The decodeStream contract is that we have already allocated 
     the pad rect, but if the bitmap does not had a ninepatch chunk, 
     then the pad will be ignored. If we could change this to lazily 
     alloc/assign the rect, we could avoid the GC churn of making new 
     Rects only to drop them on the floor. 
    */ 
    Rect pad = new Rect(); 

    // Special stuff for compatibility mode: if the target density is not 
    // the same as the display density, but the resource -is- the same as 
    // the display density, then don't scale it down to the target density. 
    // This allows us to load the system's density-correct resources into 
    // an application in compatibility mode, without scaling those down 
    // to the compatibility density only to have them scaled back up when 
    // drawn to the screen. 
    if (opts == null) opts = new BitmapFactory.Options(); 
    opts.inScreenDensity = Drawable.resolveDensity(res, 0); 
    Bitmap bm = BitmapFactory.decodeResourceStream(res, value, is, pad, opts); 
    if (bm != null) { 
     byte[] np = bm.getNinePatchChunk(); 
     if (np == null || !NinePatch.isNinePatchChunk(np)) { 
      np = null; 
      pad = null; 
     } 

     final Rect opticalInsets = new Rect(); 
     bm.getOpticalInsets(opticalInsets); 
     return drawableFromBitmap(res, bm, np, pad, opticalInsets, srcName); 
    } 
    return null; 
} 

а также, в draw(Canvas canvas) методе BitmapDrawable рисунок делается с этой линии:

canvas.drawBitmap(bitmap, null, mDstRect, paint); 

похоже, что Bitmap используется как он есть, это назначение Rect, что делает масштабирование

EDIT

Сегодня я случайно обнаружил еще одну интересную вещь, я положил изображение в вытяжке папке (неопределенные плотности) и извлекается Картинку с BitmapFactory.decodeResourceStream(res, value, is, pad, opts), такой же, как выше. Растровое изображение, которое я получил, было намного больше, чем изображение в выпадающей папке, я думаю, что если плотность будет неопределенной, она будет принимать mdpi и даже будет увеличивать растровое изображение для более высокой плотности целевого объекта.

+0

Хорошее представление об испытаниях с огромным png. – tir38

+0

спасибо, подготовитесь, чтобы увидеть, как он взорвался :) Я также обнаружил что-то новое сегодня, я положил его в ответ – lelloman

+0

Да, попробовал огромное изображение и: бум :. Кроме того, то, что вы говорите о размере изображения в неопределенной плотности, намекается на этот похожий вопрос: http://stackoverflow.com/a/13120950/1650674. Что произойдет, если вы включите «drawable-nodpi»? – tir38