31
Displaying Images How to manage images nicely +RobertoOrgiu @_tiwiz +MatteoBonifazi @mbonifazi

Android - Displaying images

Embed Size (px)

Citation preview

Page 1: Android - Displaying images

Displaying ImagesHow to manage images nicely

+RobertoOrgiu@_tiwiz

+MatteoBonifazi@mbonifazi

Page 2: Android - Displaying images

Pictures are faster than wordsConsider using pictures to explain ideas. They get

people's attention and can be much more efficient than words.

Page 3: Android - Displaying images

For media rich applications, BITMAPS are everywhere.

Page 4: Android - Displaying images

Handling BitmapsLoading bitmaps in app is tricky

● Bitmaps can very easily exhaust an app's memory budget.● Loading bitmaps on the UI thread can degrade your app's

performance● If your app is loading multiple bitmaps into memory, you

need to skillfully manage memory and disk caching.

Page 5: Android - Displaying images

Loading Large Bitmaps Efficiently

Page 6: Android - Displaying images

Images come in all shapes and sizes. In many cases they are larger than required for a

typical application user interface (UI).

Page 7: Android - Displaying images

Read bitmap dimensions and type

BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeResource(getResources(), R.id.myimage, options);int imageHeight = options.outHeight;int imageWidth = options.outWidth;String imageType = options.outMimeType;

The BitmapFactory class provides several decoding methods (decodeByteArray(),

decodeFile(), decodeResource(), etc.) for creating a Bitmap from various sources

To avoid java.lang.OutOfMemory exceptions, check the dimensions of a

bitmap before decoding it.

Page 8: Android - Displaying images

Load a Scaled Down Version into Memory 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) { //Downsize of the resources

final int halfHeight = height / 2; final int halfWidth = width / 2; while ((halfHeight / inSampleSize) >= reqHeight &&

(halfWidth / inSampleSize) >= reqWidth) { inSampleSize *= 2; } } return inSampleSize;}

A power of two value is calculated because the decoder uses a final value by rounding down to the nearest power of two, as per

the inSampleSize documentation.

Page 9: Android - Displaying images

Decode the images

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);}

If set to true, the decoder will return null (no bitmap), but the out... fields will still be set,

allowing the caller to query the bitmap without having to allocate the memory for its pixels.

Page 10: Android - Displaying images

Load the image into the ImageView

mImageView.setImageBitmap( decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));

Page 11: Android - Displaying images

Caching bitmaps

Page 12: Android - Displaying images

Load a new bitmap for your apps’ social media stream, or whatever, but you're out of memory.

Page 13: Android - Displaying images

Use a Memory CacheLRU Cache for all of us

This container keeps a list of objects, and ranks them based upon how many times they’ve been accessed. When it’s time to evict one of them (to make space for a new object) the LRUCache already knows which ones to get rid of. All done without you having to worry about any of it.

Page 14: Android - Displaying images

Suitable size for a LruCache Factors should be taken into consideration

● How memory intensive is the rest of your activity and/or application?

● How many images will be on-screen at once? ● How many need to be available ready to come on-screen?● What is the screen size and density of the device? ● What dimensions and configuration are the bitmaps?● How frequently will the images be accessed?

Page 15: Android - Displaying images

There is no ONE SOLUTION!

Avoid java.lang.OutOfMemory exceptions

Page 16: Android - Displaying images

Memory LRU cache

private LruCache<String, Bitmap> mMemoryCache;

protected void onCreate(Bundle savedInstanceState) { final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); // Use 1/8th of the available memory for this memory cache. final int cacheSize = maxMemory / 8;

mMemoryCache = new LruCache<String, Bitmap>(cacheSize) { @Override protected int sizeOf(String key, Bitmap bitmap) { // The cache size will be measured in kilobytes

// rather than number of items. return bitmap.getByteCount() / 1024; } };

Get max available VM memory, exceeding this amount will throw anOutOfMemory exception. Stored in

kilobytes as LruCache takes anint in its constructor.

Page 17: Android - Displaying images

Memory LRU cache

// Add bitmap to the cache public void addBitmapToMemoryCache(String key, Bitmap bitmap) { if (getBitmapFromMemCache(key) == null) { mMemoryCache.put(key, bitmap); }}//Retrieve the bitmap from the cachepublic Bitmap getBitmapFromMemCache(String key) { return mMemoryCache.get(key);}

Page 18: Android - Displaying images

Disk LRU cache

private DiskLruCache mDiskLruCache;private static final int DISK_CACHE_SIZE = 1024 * 1024 * 10; // 10MB

protected void onCreate(Bundle savedInstanceState) { // Initialize disk cache on background thread File cacheDir = getDiskCacheDir(this, "thumbnails"); new InitDiskCacheTask().execute(cacheDir);}class InitDiskCacheTask extends AsyncTask<File, Void, Void> { protected Void doInBackground(File... params) { synchronized (mDiskCacheLock) { File cacheDir = params[0]; mDiskLruCache = DiskLruCache.open(cacheDir, DISK_CACHE_SIZE); } ....

Page 19: Android - Displaying images

Disk LRU cache

public void addBitmapToCache(String key, Bitmap bitmap) { if (getBitmapFromMemCache(key) == null) { // Add to memory cache as before mMemoryCache.put(key, bitmap); } synchronized (mDiskCacheLock) { // Also add to disk cache if (mDiskLruCache != null && mDiskLruCache.get(key) == null) { mDiskLruCache.put(key, bitmap); } ...public Bitmap getBitmapFromDiskCache(String key) { synchronized (mDiskCacheLock) { while (mDiskCacheStarting) {// Wait while disk cache is started

try { mDiskCacheLock.wait(); } …. if (mDiskLruCache != null) { return mDiskLruCache.get(key); }....

Page 20: Android - Displaying images

Disk LRU cache

final String imageKey = String.valueOf(params[0]);

// Check disk cache in background threadBitmap bitmap = getBitmapFromDiskCache(imageKey);

if (bitmap == null) { // Not found in disk cache // Process as normal final Bitmap bitmap = decodeSampledBitmapFromResource(getResources(), params[0], 100, 100));}

// Add final bitmap to cachesaddBitmapToCache(imageKey, bitmap);

Page 22: Android - Displaying images

Can we do it faster?

Page 23: Android - Displaying images

YesWe can!

● Picasso● Glide

Page 24: Android - Displaying images

Importing the libraries

compile 'com.squareup.picasso:picasso:2.5.2'

compile 'com.github.bumptech.glide:glide:3.7.0'

Page 25: Android - Displaying images

Loading the images simply

Picasso.with(context) .load(urlOfTheImageAsString) .into(imageView);

Page 26: Android - Displaying images

Loading the images simply

Picasso.with(context) .load(R.drawable.ic_image) .into(imageView);

Page 27: Android - Displaying images

Loading the images simply

Picasso.with(context) .load(“file:///android_assets/amazing.png”) .into(imageView);

Page 28: Android - Displaying images

Loading the images simply

Picasso.with(context) .load(new File(...)) .into(imageView);

Page 29: Android - Displaying images

Managing waiting state and errors

Picasso.with(context) .load(urlOfTheImageAsString) .placeholder(R.drawable.placeholder) .error(R.drawable.error) .into(imageView);

Page 30: Android - Displaying images

Advanced features

Picasso.with(context) .load(url) .resize(50, 50) .centerCrop() .into(imageView)

Page 31: Android - Displaying images

+MatteoBonifazi@mbonifazi

Thank You!

+RobertoOrgiu@_tiwiz