Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Picasso sat up !

Picasso sat up !

We all love and use Picasso - An image caching and downloading library in android. This talk covered all the new upcoming features & internal implementation changes done in the newer version of Picasso 3.0 after 3 years. I covered few important changes,

INTERNAL IMPLEMENTATION CHANGES :

* Android P - ImageDecoder support
* Network upgrade - okhttp2 -> okhttp3
* Okio integration

NEW FEATURES IN LIBRARY :

* Context removal
* Callback changes
* Target changes
* Lifecycle awareness & more..

Avatar for Ramkishore V S

Ramkishore V S

December 01, 2018
Tweet

Other Decks in Programming

Transcript

  1. HISTORICAL OVERVIEW ▸ Before image loading libraries - let’s take

    a look how we came to this in evolutional stages.
  2. EVOLUTION 1 URL url = null; try { url =

    new URL(urlList.get(0)); } catch (MalformedURLException e) { e.printStackTrace(); } HttpURLConnection con= (HttpURLConnection) url.openConnection(); Bitmap bitmap = null; try { bitmap = BitmapFactory.decodeFile(con.getInputStream()); } catch (IOException e) { e.printStackTrace(); } mImageView.setImageBitmap(bitmap);
  3. SOLUTION - 2 private class DownloadImageTask extends AsyncTask<URL,Bitmap,Bitmap> { protected

    Bitmap doInBackground(URL... urls) { URL url = null; try { url = new URL(urlList.get(0)); } catch (MalformedURLException e) { e.printStackTrace(); } HttpURLConnection con= null; try { con = (HttpURLConnection) url.openConnection(); } catch (IOException e) { e.printStackTrace(); } try { return BitmapFactory.decodeFile(con.getInputStream()); } catch (IOException e) { e.printStackTrace(); } } protected void onPostExecute(Bitmap result) { mImageView.setImageBitmap(result) } }
  4. SOLUTION - 3 ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo info

    = cm.getNetworkInfo(context); if(info != null && info.isConnected()){ new DownloadImageTask().execute(image_url)); } else { mImageView.setImageResources(error_image); }
  5. NEXT EVOLUTION? ▸ What about applying transformation?? ▸ How about

    rotating the image?? ▸ How about about caching the image to reduce the network call??
  6. BIRTH OF IMAGE LOADING LIBRARIES ▸ Then came lot of

    image loading libraries like Glide, Picasso, Fresco etc..
  7. PICASSO ▸ Image caching and downloading library. ▸ Does all

    the stuff in a one line, one jar. ▸ Built by Square back in 2013. ▸ Has a lot of things ranging from resizing, target manipulations, etc..
  8. SOME HANDLED PITFALLS ▸ Handling ImageView recycling and download cancelation

    in an adapter. ▸ Complex image transformations with minimal memory use. ▸ Automatic memory and disk caching.
  9. SOME FEATURES IN 2015 - ISH ▸ Adapter Downloads ▸

    Image Transformations ▸ Debug Indicators
  10. ADAPTER DOWNLOADS @Override public void getView(int position, View convertView, ViewGroup

    parent) { SquaredImageView view = (SquaredImageView) convertView; if (view == null) { view = new SquaredImageView(context); } String url = getItem(position); Picasso.get().load(url).into(view); } Adapter re-use is automatically detected and the previous download is canceled.
  11. CUSTOM TRANSFORMATION public class CropSquareTransformation implements Transformation { @Override public

    Bitmap transform(Bitmap source) { int size = Math.min(source.getWidth(), source.getHeight()); int x = (source.getWidth() - size) / 2; int y = (source.getHeight() - size) / 2; Bitmap result = Bitmap.createBitmap(source, x, y, size, size); if (result != source) { source.recycle(); } return result; } @Override public String key() { return "square()"; } }
  12. REPRESENTATIONS ▸ Picasso Indicators show source (memory, disk or network)

    ▸ green (memory, best performance) ▸ blue (disk, good performance) ▸ red (network, worst performance).
  13. PEOPLE STARTED COMPLAINING ▸ There are lot of bugs ▸

    New features are missing ▸ Not maintained actively ▸ Google doesn’t recommend this
  14. SOME COOL DIFFERENCES ▸ ImageDecoder isn't just about bitmaps. ▸

    bytes[] -> drawables, bitmaps much more.. ▸ Decodes animated image files & returns a AnimatedImageDrawable type. ▸ Google calls it more efficient.
  15. INTERNAL IMPLEMENTATION CHANGES fun updateAsset(context: Context) { launch(CommonPool) { ImageDecoder.createSource(cacheAsset.file(assetName)).also

    { source -> ImageDecoder.decodeDrawable(source).also { drawable -> launch(UI) { image.setImageDrawable(drawable) if (drawable is Animatable2) { drawable.start() } } } } } }
  16. PERKS IN NEW ADDITION ▸ Write asynchronous code unlike before.

    ▸ okhttp3 supports Call.Factory just like retrofit allowing us to have abstraction on top of HTTP clients.
  17. INTERNAL IMPLEMENTATION DETAILS ▸ 1. Using Android P feature. ▸

    2. The network upgrade. ▸ 3. okio integration - access, store and process your data.
  18. WHAT ACTUALLY COMPOSES OF AN IMAGE ? UNDERTAKER.PNG MAGIC METADATA

    METADATA PIXEL DATA PIXEL DATA PIXEL DATA
  19. THE SOLUTION - PUSH BACK PROBLEM MAGIC METADATA METADATA PIXEL

    DATA METADATA PIXEL DATA BitmapFactory InputStream 2k chunks METADATA PIXEL DATA png 1920 x 1080
  20. PARTS PROCESSED ▸ Magic bit - we have the image

    type. ▸ Meta data - The width & height is returned to the caller. ▸ What we don’t have is complete pixel data.
  21. THE COMPLETE PIXEL QUERY PROBLEM ▸ We still have to

    do the real decoding as we don’t have all the pixel data. ▸ BitmapFactory has already taken 2k chunk of bytes. As we are in middle of data already we can’t have a new BitmapFactory to do things for us.
  22. THE SOLUTION - COMPLETE PIXEL QUERY PROBLEM METADATA MAGIC METADATA

    METADATA METADATA PIXEL DATA BitmapFactory MarkableInputStream PIXEL DATA PIXEL DATA PIXEL DATA PIXEL DATA InputStream PIXEL DATA
  23. THE RESET PROBLEM ▸ Sometimes in some images (usually jpeg)

    when do header decoding BitmapFactory goes on processing despite reading all the meta data and failing to get the size. ▸ Results in consuming the complete MarkableInputStream.
  24. THE RESET PROBLEM METADATA MAGIC METADATA METADATA METADATA PIXEL DATA

    BitmapFactory MarkableInputStream PIXEL DATA PIXEL DATA PIXEL DATA PIXEL DATA InputStream PIXEL DATA
  25. THE RESET PROBLEM PIXEL DATA PIXEL DATA PIXEL DATA PIXEL

    DATA PIXEL DATA PIXEL DATA BitmapFactory PIXEL DATA PIXEL DATA PIXEL DATA MarkableInputStream PIXEL DATA InputStream PIXEL DA
  26. SOLUTION - RESET PROBLEM METADATA PIXEL DATA PIXEL DATA PIXEL

    DATA MAGIC BitmapFactory SourceBufferingInputStream offset :1024 METADATA PIXEL DATA PIXEL DATA BufferedSource METADATA MAGIC METADA PIXEL DATA
  27. SOLUTION - RESET PROBLEM (not able to figure out??) BitmapFactory

    SourceBufferingInputStream offset :3754 METADATA MAGIC METADA BufferedSource
  28. IMAGE ROTATION FEATURE ▸ Earlier android APIs wanted to store

    it in a file system which would be heavy and time consuming close to a second. ▸ But now we can make use of the same BufferedSource that Okio provides to read the InputStream multiple times but from ExifInterface. ▸ This enables us to do rotation of images little quick.
  29. USING THE PICASSO - 3.0 maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }

    dependencies { implementation 'com.squareup.picasso3:picasso:3.0.0-SNAPSHOT' }
  30. NO MORE CONTEXT ! val urlList = Arrays.asList( "http://i.imgur.com/UZFOMzL.jpg", "http://i.imgur.com/H981AN7.jpg",

    "http://i.imgur.com/nwhnRsZ.jpg", “http://i.imgur.com/MU2dD8E.jpg") Picasso.get().load(urlList.get(0)).into(target)
  31. REMOVE OKHTTP3 HACKS ▸ If you've implemented a custom downloader

    to use Picasso 2.5.2 with OkHttp 3 as the network stack, you can remove that from your code base. It's not necessary anymore!
  32. TARGET CHANGE val target = object : Target() { fun

    onBitmapLoaded(bitmap: Bitmap, from: Picasso.LoadedFrom) {} fun onBitmapFailed(e: Exception, errorDrawable: Drawable) { //TODO do some action/warning/error message, now with exception. } fun onPrepareLoad(placeHolderDrawable: Drawable) {} }
  33. LIFECYCLE AWARENESS /** * Image downloading, transformation, and caching manager.

    * <p> * Use {@see PicassoProvider#get()} for a global singleton instance * or construct your own instance with {@link Builder}. */ public class Picasso implements LifecycleObserver { }
  34. LIFECYCLE MAGIC @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) void cancelAll() { checkMain(); List<Action> actions =

    new ArrayList<>(targetToAction.values()); for (int i = 0, n = actions.size(); i < n; i++) { Action action = actions.get(i); cancelExistingRequest(action.getTarget()); } List<DeferredRequestCreator> deferredRequestCreators = new ArrayList<>(targetToDeferredRequestCreator.values()); for (int i = 0, n = deferredRequestCreators.size(); i < n; i++) { DeferredRequestCreator deferredRequestCreator = deferredRequestCreators.get(i); deferredRequestCreator.cancel(); } }
  35. HTTP HEADERS (IN PROGRESS) ▸ Soon we’ll be able to

    add HTTP headers to our requests in Picasso through okhttp3.Headers class. ▸ The reason for choosing okhttp3.Headers over a map is that its more immutable & map allows untyped values which we don't want at the requests.
  36. SUMMARY - INTERNAL IMPLEMENTATIONS ▸ Android P feature - ImageDecoder.

    ▸ The network upgrade. (okHttp3) ▸ Okio integration
  37. SUMMARY - NEW FEATURES ▸ No more context ▸ Callback

    changes ▸ Target changes ▸ Lifecycle awareness ▸ HTTP headers support (coming soon)