Rinsing the Brush – Picasso 3.0 (Droidcon NYC 2018)

Rinsing the Brush – Picasso 3.0 (Droidcon NYC 2018)

Picasso is a powerful image downloading and caching library for Android but since its launch in 2013, other libraries have improved or entered the scene and new requirements have come up.

In this talk, we’ll:

* Dig into the internals of how Picasso works
* Explore ImageDecoder, BitmapFactory's successor in Android P
* Compare and contrast to other image libraries
* Discuss latest improvements as we push to 3.0
…and more!

You’ll learn to efficiently work with different image formats across millions of devices!

Video: https://youtu.be/VpNwLG3lxbo

E68309f117985270285ade8082f4877d?s=128

Jake Wharton

August 27, 2018
Tweet

Transcript

  1. Rinsing the Brush: Picasso 3.0 John Rodriguez Jake Wharton

  2. None
  3. None
  4. None
  5. None
  6. None
  7. 3 years later

  8. 3.x Goals

  9. • Android P 3.x Goals

  10. • Android P • Improvements 3.x Goals

  11. • Android P • Improvements • OkHttp 2.x => 3.x

    3.x Goals
  12. • Android P • Improvements • OkHttp 2.x => 3.x


    • Okio integration 3.x Goals
  13. • Android P • Improvements • OkHttp 2.x => 3.x


    • Okio integration 3.x Goals
  14. None
  15. None
  16. Bitmap decodeStreamPreP(Request r, BufferedSource bs) { BitmapFactory.Options options = createBitmapOptions(request);

    if (requiresInSampleSize(options)) { InputStream stream = new SourceBufferingInputStream(bs); BitmapFactory.decodeStream(stream, null, options); calculateInSampleSize(r.targetWidth, r.targetHeight, options, r); } return BitmapFactory.decodeStream(bs.inputStream(), null, options); }
  17. Bitmap decodeStreamPreP(Request r, BufferedSource bs) { BitmapFactory.Options options = createBitmapOptions(request);

    if (requiresInSampleSize(options)) { InputStream stream = new SourceBufferingInputStream(bs); BitmapFactory.decodeStream(stream, null, options); calculateInSampleSize(r.targetWidth, r.targetHeight, options, r); } return BitmapFactory.decodeStream(bs.inputStream(), null, options); }
  18. None
  19. Bitmap decodeStreamP(Request r, BufferedSource bs) { ImageDecoder.Source imageSource = ImageDecoder.createSource(ByteBuffer.wrap(bs.readByteArray()));

    return ImageDecoder.decodeBitmap( imageSource, (imageDecoder, imageInfo, src) -> { if (r.hasSize()) { imageDecoder.setTargetSize(r.targetWidth, r.targetHeight); } } }); }
  20. Bitmap decodeStreamP(Request r, BufferedSource bs) { ImageDecoder.Source imageSource = ImageDecoder.createSource(ByteBuffer.wrap(bs.readByteArray()));

    return ImageDecoder.decodeBitmap( imageSource, (imageDecoder, imageInfo, src) -> { if (r.hasSize()) { imageDecoder.setTargetSize(r.targetWidth, r.targetHeight); } } }); }
  21. Bitmap decodeStreamP(Request r, BufferedSource bs) { ImageDecoder.Source imageSource = ImageDecoder.createSource(ByteBuffer.wrap(bs.readByteArray()));

    return ImageDecoder.decodeBitmap( imageSource, (imageDecoder, imageInfo, src) -> { if (r.hasSize()) { imageDecoder.setTargetSize(r.targetWidth, r.targetHeight); } } }); }
  22. • Android P • Improvements • OkHttp 2.x => 3.x


    • Okio integration 3.x Goals
  23. Picasso

  24. Picasso picasso.load(url) .placeholder(R.drawable.placeholder) .error(R.drawable.error) .fit() .into(view);

  25. Picasso

  26. Picasso fun loadImage( remoteUri: Uri, @ColorInt tintColor: Int? = null

    ) { val creator = picasso.load(remoteUri) .placeholder(avatarPlaceholder) .fit() if (transformTintColor != null) { creator.transform(TintTransformation(tintColor)) } creator.into(this) }
  27. Picasso fun loadImage( awsAssetUri: Uri, height: Int, width: Int )

    { val creator = picasso.load(awsAssetUri) .placeholder(avatarPlaceholder) .fit() .into(this) }
  28. Picasso fun loadImage( awsAssetUri: Uri, height: Int, width: Int )

    { val creator = picasso.load(awsAssetUri) .placeholder(avatarPlaceholder) .fit() .into(this) }
  29. None
  30. Picasso picasso.load(“http://shrek.jpg”) .placeholder(R.drawable.placeholder) .error(R.drawable.error) .fit() .into(view);

  31. Picasso Request “http://shrek.jpg”

  32. Picasso Request Request Transformer Request “http://shrek.jpg”

  33. Picasso Request “http://shrek.jpg” Request Transformer Request “http://bar.com/20x20/shrek.jpg”

  34. p://shrek.jpg

  35. 0101011010100 http://shrek.jpg

  36. 0101011010100 http://shrek.jpg

  37. 01010110101001101

  38. 01010110101001101

  39. 01010110101001101

  40. 01 01 0110 10100 1 1 0 1

  41. 01 01 0110 10100 1 1 0 1

  42. None
  43. None
  44. 0x20/shrek.jpg

  45. http://bar.com/20x20/shrek.jpg

  46. http://bar.com/20x20/shrek.jpg

  47. 0101011

  48. 0101011

  49. 0101011

  50. 0101011

  51. 0101011

  52. 01 010 1 1

  53. 01 010 1 1

  54. 01 010 1 1

  55. None
  56. None
  57. None
  58. None
  59. ?

  60. None
  61. None
  62. None
  63. /** * Sets the stable key for this request to

    be used instead of the * URI or resource ID when caching. * Two requests with the same value are considered to be for the * same resource. */ public RequestCreator stableKey(String stableKey) { data.stableKey(stableKey); return this; }
  64. createNewPicasso(context, 1024, new CustomRequestHandler()); Picasso createNewPicasso( Context context, int cacheSize,

    RequestHandler requestHandler ) {e return new Picasso.Builder(context) e.withCacheSize(cacheSize) e.addRequestHandler(requestHandler) e.build(); }e
  65. createChildPicasso(builder, 1024, new CustomRequestHandler()); Picasso createChildPicasso( Picasso.Builder builder, int cacheSize,

    RequestHandler requestHandler ) { return builder .withCacheSize(cacheSize) .addRequestHandler(requestHandler) .build(); }e
  66. createChildPicasso(picasso, 1024, new CustomRequestHandler()); Picasso createChildPicasso( Picasso picasso, int cacheSize,

    RequestHandler requestHandler ) { return picasso.newBuilder() .withCacheSize(cacheSize) .addRequestHandler(requestHandler) .build(); }e builder Picasso.Builder builder, builder
  67. createChildPicasso(picasso, 1024, new CustomRequestHandler()); Picasso createChildPicasso( Picasso picasso, int cacheSize,

    RequestHandler requestHandler ) { return picasso.newBuilder() .withCacheSize(cacheSize) .addRequestHandler(requestHandler) .build(); }
  68. @Component( modules = RootModule.class ) @RootScope interface RootComponent { @Root

    Picasso picasso(); } @Module class RootModule { @Provides @RootScope @Root Picasso providePicasso(@App Context context) { return new Picasso.Builder(context) .withCacheSize(1024*1024) .build(); } }
  69. @Component( modules = RootModule.class ) @RootScope interface RootComponent { @Root

    Picasso picasso(); } @Module class RootModule { @Provides @RootScope @Root Picasso providePicasso(@App Context context) { return new Picasso.Builder(context) .withCacheSize(1024*1024) .build(); } }
  70. @Component( modules = RootModule.class ) @RootScope interface RootComponent { @Root

    Picasso picasso(); } @Module class RootModule { @Provides @RootScope @Root Picasso providePicasso(@App Context context) { return new Picasso.Builder(context) .withCacheSize(1024*1024) .build(); } }
  71. @Component( dependencies = RootComponent.class, modules = ScreenModule.class ) @ScreenScope interface

    ScreenComponent { } @Module class ScreenModule { @Provides @ScreenScope @Screen Picasso providePicasso(@Root Picasso picasso) { return picasso.newBuilder() .withCacheSize(1024) .build(); } }
  72. @Component( dependencies = RootComponent.class, modules = ScreenModule.class ) @ScreenScope interface

    ScreenComponent { } @Module class ScreenModule { @Provides @ScreenScope @Screen Picasso providePicasso(@Root Picasso picasso) { return picasso.newBuilder() .withCacheSize(1024) .build(); } }
  73. @Component( dependencies = RootComponent.class, modules = ScreenModule.class ) @ScreenScope interface

    ScreenComponent { } @Module class ScreenModule { @Provides @ScreenScope @Screen Picasso providePicasso(@Root Picasso picasso) { return picasso.newBuilder() .withCacheSize(1024) .build(); } }
  74. @Component( dependencies = RootComponent.class, modules = ScreenModule.class ) @ScreenScope interface

    ScreenComponent { } @Module class ScreenModule { @Provides @ScreenScope @Screen Picasso providePicasso(@Root Picasso picasso) { return picasso.newBuilder() .withCacheSize(1024) .build(); } }
  75. None
  76. None
  77. /** * Image downloading, transformation, and caching manager. * *

    Use {@see PicassoProvider#get()} for a global singleton * instance or construct your own instance with {@link Builder}. */ public class Picasso implements LifecycleObserver { }
  78. /** * Image downloading, transformation, and caching manager. * *

    Use {@see PicassoProvider#get()} for a global singleton * instance or construct your own instance with {@link Builder}. */ public class Picasso implements LifecycleObserver { }
  79. class SampleActivity extends FragmentActivity { protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState); … getLifecycle().addObserver(picasso); }
  80. class SampleActivity extends FragmentActivity { protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState); … getLifecycle().addObserver(picasso); }
  81. @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) void cancelAll() { List<Action> actions = new ArrayList<>(targetToAction.values()); for

    (int i = 0, n = actions.size(); i < n; i++) { cancelExistingRequest(actions.get(i).getTarget()); } List<DeferredRequestCreator> deferredRequestCreators = new ArrayList<>(targetToDeferredRequestCreator.values()); for (int i = 0, n = deferredCreators.size(); i < n; i++) { deferredCreators.get(i).cancel(); } }
  82. Picasso Request “http://shrek.jpg” Request Transformer Request’ “http://bar.com/20x20/shrek.jpg”

  83. Picasso Request Transformer

  84. ResourceRequestHandler AssetsRequestHandler NetworkRequestHandler FileRequestHandler Picasso Request Transformer

  85. Picasso Request Transformer Handler Request Resource AssetsRequestHandler NetworkRequestHandler FileRequestHandler

  86. Picasso Request Transformer Handler Request

  87. Picasso Request Transformer Request Handler Bitmap

  88. Bitmap Drawable Result Picasso Request Transformer Request Handler

  89. Picasso Request Transformer Result Request Handler Greyscale Circle Tint

  90. Greyscale Circle Tint Picasso Request Transformer Result Request Handler Transformation

  91. Picasso Request Transformer Result Target Request Handler Transformation

  92. Request Transformer Result Request Handler Transformation

  93. Transformer Result Transformer Transformer

  94. Transformer Transformer Transformer

  95. Transformer Transformer Transformer

  96. Transformer Transformer Transformer

  97. custom interceptors Retry Bridge Cache Connect Call Server square/okhttp

  98. None
  99. None
  100. @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Picasso.with(this) .load("http://example.com/logo.png")

    .into(imageView); }
  101. @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Picasso.with(this) .load("http://example.com/logo.png")

    .into(imageView); }
  102. public static Picasso with(Context context) { if (singleton == null)

    { synchronized (Picasso.class) { if (singleton == null) { singleton = new Builder(context).build(); } } } return singleton; }
  103. public static Picasso with(Context context) { if (singleton == null)

    { synchronized (Picasso.class) { if (singleton == null) { singleton = new Builder(context).build(); } } } return singleton; }
  104. public static void setSingletonInstance(Picasso picasso) { synchronized (Picasso.class) { if

    (singleton != null) { throw new IllegalStateException( "Singleton instance already exists."); } singleton = picasso; } }
  105. public static void setSingletonInstance(Picasso picasso) { synchronized (Picasso.class) { if

    (singleton != null) { throw new IllegalStateException( "Singleton instance already exists."); } singleton = picasso; } }
  106. @Module(includes = ThumborModule.class) final class ProductionPicassoModule { @Provides @Singleton static

    Picasso providePicasso( @App Context context, OkHttpClient client, Thumbor thumbor) { Picasso.RequestTransformer transformer = new PollexorRequestTransformer(thumbor); return new Picasso.Builder(context) .client(client) .requestTransformer(transformer) .listener((picasso, uri, e) -> Timber.d(e, uri.toString())); } }
  107. @Module(includes = ThumborModule.class) final class ProductionPicassoModule { @Provides @Singleton static

    Picasso providePicasso( @App Context context, OkHttpClient client, Thumbor thumbor) { Picasso.RequestTransformer transformer = new PollexorRequestTransformer(thumbor); return new Picasso.Builder(context) .client(client) .requestTransformer(transformer) .listener((picasso, uri, e) -> Timber.d(e, uri.toString())); } }
  108. None
  109. None
  110. public final class PicassoProvider { private static volatile Picasso instance;

    public static Picasso get() { if (instance == null) { synchronized (PicassoProvider.class) { if (instance == null) { if (PicassoContentProvider.context == null) { throw new IllegalStateException("context == null"); } instance = new Picasso.Builder(PicassoContentProvider.context).build(); } } } return instance; } }
  111. public final class PicassoProvider { private static volatile Picasso instance;

    public static Picasso get() { if (instance == null) { synchronized (PicassoProvider.class) { if (instance == null) { if (PicassoContentProvider.context == null) { throw new IllegalStateException("context == null"); } instance = new Picasso.Builder(PicassoContentProvider.context).build(); } } } return instance; } }
  112. public final class PicassoProvider { private static volatile Picasso instance;

    public static Picasso get() { if (instance == null) { synchronized (PicassoProvider.class) { if (instance == null) { if (PicassoContentProvider.context == null) { throw new IllegalStateException("context == null"); } instance = new Picasso.Builder(PicassoContentProvider.context).build(); } } } return instance; } }
  113. public final class PicassoContentProvider extends ContentProvider { static Context context;

    @Override public boolean onCreate() { context = getContext(); return true; } … }
  114. None
  115. <activity android:name=".Issue1955" android:process="not-the-main-process" > <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter>

    </activity>
  116. None
  117. None
  118. interface ImageDecoder { class Image { @Nullable Bitmap bitmap; @Nullable

    Drawable drawable; int exifOrientation; } boolean canHandleSource(BufferedSource source); Image decodeImage(BufferedSource source, Request request) throws IOException; }
  119. class ImageDecoderFactory { List<ImageDecoder> decoders; ImageDecoder getImageDecoderForSource(BufferedSource source) { for

    (ImageDecoder decoder : decoders) { if (decoder.canHandleSource(source)) { return decoder; } } return null; } }
  120. Picasso

  121. Picasso?

  122. • Android P
 • Improvements • OkHttp 2.x => 3.x


    • Okio integration 3.x Goals
  123. Picasso

  124. Picasso ResourceRequestHandler AssetsRequestHandler NetworkRequestHandler FileRequestHandler ...

  125. Downloader Picasso ResourceRequestHandler AssetsRequestHandler NetworkRequestHandler FileRequestHandler ...

  126. OkHttp 2.x HttpURLConnection Downloader Picasso ResourceRequestHandler AssetsRequestHandler NetworkRequestHandler FileRequestHandler ...

  127. OkHttp 2.x HttpURLConnection OkHttp 3.x Downloader Picasso ResourceRequestHandler AssetsRequestHandler NetworkRequestHandler

    FileRequestHandler ...
  128. OkHttp 3.x HttpURLConnection OkHttp 2.x Downloader Picasso ResourceRequestHandler AssetsRequestHandler NetworkRequestHandler

    FileRequestHandler ...
  129. OkHttp 3.x Picasso ResourceRequestHandler AssetsRequestHandler NetworkRequestHandler FileRequestHandler ...

  130. Picasso ResourceRequestHandler AssetsRequestHandler NetworkRequestHandler FileRequestHandler ... Call.Factory (OkHttp 3.x)

  131. Picasso OkHttp

  132. Okio Picasso OkHttp

  133. Picasso OkHttp Retrofit Okio

  134. Picasso OkHttp Okio Retrofit Moshi

  135. Picasso OkHttp Okio Retrofit Moshi

  136. Picasso OkHttp Okio Retrofit Moshi Wire

  137. Picasso OkHttp Okio Retrofit Moshi Wire

  138. • Android P • Improvements • OkHttp 2.x => 3.x


    • Okio integration 3.x Goals
  139. java.io.IOException: Cannot reset at com.squareup.picasso.MarkableInputStream.reset(MarkableInputStream.java:99) at com.squareup.picasso.BitmapHunter.decodeStream(BitmapHunter.java:140) at com.squareup.picasso.BitmapHunter.hunt(BitmapHunter.java:217) at

    com.squareup.picasso.BitmapHunter.run(BitmapHunter.java:159) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:457) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) at java.lang.Thread.run(Thread.java:764) at com.squareup.picasso.Utils$PicassoThread.run(Utils.java:411)
  140. nightmare_shrek.png

  141. MAGIC nightmare_shrek.png

  142. METADATA METADATA METADATA MAGIC nightmare_shrek.png

  143. PIXEL DATA PIXEL DATA PIXEL DATA PIXEL DATA PIXEL DATA

    PIXEL DATA PIXEL DATA PIXEL DATA PIXEL DATA METADATA METADATA METADATA MAGIC nightmare_shrek.png
  144. PIXEL DATA PIXEL DATA PIXEL DATA PIXEL DATA PIXEL DATA

    PIXEL DATA PIXEL DATA PIXEL DATA PIXEL DATA METADATA METADATA METADATA MAGIC
  145. PIXEL DATA PIXEL DATA PIXEL DATA PIXEL DATA PIXEL DATA

    PIXEL DATA PIXEL DATA PIXEL DATA PIXEL DATA METADATA METADATA METADATA MAGIC
  146. PIXEL DATA PIXEL DATA PIXEL DATA PIXEL DATA PIXEL DATA

    PIXEL DATA PIXEL DATA PIXEL DATA PIXEL DATA METADATA METADATA METADATA MAGIC
  147. PIXEL DATA PIXEL DATA PIXEL DATA PIXEL DATA PIXEL DATA

    PIXEL DATA PIXEL DATA PIXEL DATA PIXEL DATA METADATA METADATA METADATA MAGIC
  148. PIXEL DATA PIXEL DATA PIXEL DATA PIXEL DATA PIXEL DATA

    PIXEL DATA PIXEL DATA PIXEL DATA PIXEL DATA METADATA METADATA METADATA MAGIC
  149. PIXEL DATA PIXEL DATA PIXEL DATA PIXEL DATA PIXEL DATA

    PIXEL DATA PIXEL DATA PIXEL DATA PIXEL DATA METADATA METADATA METADATA MAGIC
  150. InputStream PIXEL DATA PIXEL DATA PIXEL DATA PIXEL DATA PIXEL

    DATA PIXEL DATA PIXEL DATA PIXEL DATA PIXEL DATA METADATA METADATA METADATA MAGIC
  151. InputStream BitmapFactory inJustDecodeBounds=true MAGIC METADATA

  152. InputStream BitmapFactory inJustDecodeBounds=true MAGIC METADATA

  153. InputStream BitmapFactory inJustDecodeBounds=true MAGIC METADATA

  154. InputStream BitmapFactory inJustDecodeBounds=true MAGIC METADATA JPEG?

  155. InputStream BitmapFactory inJustDecodeBounds=true MAGIC METADATA METADAT JPEG?

  156. InputStream BitmapFactory inJustDecodeBounds=true MAGIC METADATA METADAT

  157. InputStream BitmapFactory inJustDecodeBounds=true MAGIC METADATA METADAT

  158. InputStream BitmapFactory inJustDecodeBounds=true MAGIC METADATA METADAT

  159. InputStream BitmapFactory inJustDecodeBounds=true MAGIC METADATA

  160. BitmapFactory inJustDecodeBounds=true MAGIC METADATA METADATA METADATA PIXEL DATA

  161. BitmapFactory inJustDecodeBounds=true MAGIC METADATA METADATA METADATA PIXEL DATA JPEG?

  162. BitmapFactory inJustDecodeBounds=true MAGIC METADATA METADATA METADATA PIXEL DATA JPEG?

  163. BitmapFactory inJustDecodeBounds=true MAGIC METADATA METADATA METADATA PIXEL DATA JPEG?

  164. BitmapFactory inJustDecodeBounds=true MAGIC METADATA METADATA METADATA PIXEL DATA PNG?

  165. BitmapFactory inJustDecodeBounds=true MAGIC METADATA METADATA METADATA PIXEL DATA PNG?

  166. BitmapFactory inJustDecodeBounds=true MAGIC METADATA METADATA METADATA PIXEL DATA PNG!

  167. BitmapFactory inJustDecodeBounds=true MAGIC METADATA METADATA METADATA PIXEL DATA PNG size?

  168. BitmapFactory inJustDecodeBounds=true MAGIC METADATA METADATA METADATA PIXEL DATA PNG size?

  169. BitmapFactory inJustDecodeBounds=true MAGIC METADATA METADATA METADATA PIXEL DATA PNG 1920x1080!

  170. BitmapFactory inJustDecodeBounds=true MAGIC METADATA 2METADATA2 1METADATA1 PIXEL DATA PNG 1920x1080

  171. BitmapFactory inJustDecodeBounds=true MAGIC METADATA 2METADATA2 1METADATA1 PIXEL DATA 1920x1080

  172. InputStream BitmapFactory BitmapFactory inJustDecodeBounds=true MAGIC METADATA 2METADATA2 1METADATA1 PIXEL DATA

    1920x1080 PIXEL DAT
  173. InputStream BitmapFactory inJustDecodeBounds=true BitmapFactory PIXEL DATA MAGIC METADATA 2METADATA2 1METADATA1

    PIXEL DATA 1920x1080
  174. InputStream BitmapFactory inJustDecodeBounds=true BitmapFactory PIXEL DATA MAGIC METADATA 2METADATA2 1METADATA1

    PIXEL DATA 1920x1080
  175. InputStream BitmapFactory inJustDecodeBounds=true BitmapFactory PIXEL DATA MAGIC METADATA 2METADATA2 1METADATA1

    PIXEL DATA 1920x1080
  176. InputStream MAGIC METADATA

  177. InputStream BitmapFactory inJustDecodeBounds=true MAGIC METADATA

  178. BitmapFactory inJustDecodeBounds=true MAGIC METADATA METADATA METADATA PIXEL DATA MarkableInputStream

  179. BitmapFactory inJustDecodeBounds=true MAGIC METADATA METADATA METADATA PIXEL DATA MarkableInputStream MAGIC

    METADATA METADATA METADATA PIXEL DATA
  180. BitmapFactory inJustDecodeBounds=true MAGIC METADATA METADATA METADATA PIXEL DATA MarkableInputStream MAGIC

    METADATA METADATA METADATA PIXEL DATA 1920x1080
  181. BitmapFactory inJustDecodeBounds=true MAGIC METADATA METADATA METADATA PIXEL DATA MarkableInputStream MAGIC

    METADATA METADATA METADATA PIXEL DATA 1920x1080
  182. BitmapFactory inJustDecodeBounds=true MAGIC METADATA METADATA METADATA PIXEL DATA MarkableInputStream MAGIC

    METADATA METADATA METADATA PIXEL DATA 1920x1080 BitmapFactory MAGIC METADATA METADATA METADATA PIXEL DATA
  183. BitmapFactory inJustDecodeBounds=true MAGIC METADATA METADATA METADATA PIXEL DATA MarkableInputStream MAGIC

    METADATA METADATA METADATA PIXEL DATA 1920x1080 MAGIC METADATA METADATA METADATA PIXEL DATA BitmapFactory
  184. BitmapFactory inJustDecodeBounds=true MarkableInputStream MAGIC METADATA METADATA METADATA PIXEL DATA 1920x1080

    BitmapFactory
  185. PIXEL DATA PIXEL DATA PIXEL DATA BitmapFactory inJustDecodeBounds=true MarkableInputStream MAGIC

    METADATA METADATA METADATA PIXEL DATA 1920x1080 BitmapFactory
  186. PIXEL DATA PIXEL DATA PIXEL DATA BitmapFactory inJustDecodeBounds=true MarkableInputStream MAGIC

    METADATA METADATA METADATA PIXEL DATA 1920x1080 BitmapFactory PIXEL DATA PIXEL DATA PIXEL DATA
  187. PIXEL DATA PIXEL DATA PIXEL DATA BitmapFactory inJustDecodeBounds=true MarkableInputStream MAGIC

    METADATA METADATA METADATA PIXEL DATA 1920x1080 BitmapFactory PIXEL DATA PIXEL DATA PIXEL DATA
  188. MAGIC METADATA METADATA METADATA PIXEL DATA MarkableInputStream MAGIC METADATA METADATA

    METADATA PIXEL DATA
  189. BitmapFactory inJustDecodeBounds=true MAGIC METADATA METADATA METADATA PIXEL DATA MarkableInputStream MAGIC

    METADATA METADATA METADATA PIXEL DATA
  190. BitmapFactory inJustDecodeBounds=true MAGIC METADATA METADATA METADATA PIXEL DATA MarkableInputStream MAGIC

    METADATA METADATA METADATA PIXEL DATA
  191. MarkableInputStream BitmapFactory inJustDecodeBounds=true

  192. PIXEL DATA PIXEL DATA PIXEL DATA MarkableInputStream BitmapFactory inJustDecodeBounds=true

  193. PIXEL DATA PIXEL DATA PIXEL DATA MarkableInputStream BitmapFactory inJustDecodeBounds=true PIXEL

    DATA PIXEL DATA PIXEL DATA
  194. MarkableInputStream BitmapFactory inJustDecodeBounds=true

  195. MarkableInputStream BitmapFactory inJustDecodeBounds=true PIXEL DATA PIXEL DATA PIXEL DATA

  196. MarkableInputStream BitmapFactory inJustDecodeBounds=true PIXEL DATA PIXEL DATA PIXEL DATA PIXEL

    DATA PIXEL DATA PIXEL DATA
  197. MarkableInputStream BitmapFactory inJustDecodeBounds=true

  198. MarkableInputStream BitmapFactory inJustDecodeBounds=true PIXEL DATA PIXEL DATA

  199. MarkableInputStream BitmapFactory inJustDecodeBounds=true PIXEL DATA PIXEL DATA PIXEL DATA PIXEL

    DATA
  200. MarkableInputStream BitmapFactory inJustDecodeBounds=true PIXEL DATA PIXEL DATA

  201. MarkableInputStream BitmapFactory inJustDecodeBounds=true ??? PIXEL DATA PIXEL DATA

  202. MarkableInputStream BitmapFactory inJustDecodeBounds=true ??? PIXEL DATA PIXEL DATA

  203. MarkableInputStream BitmapFactory inJustDecodeBounds=true ??? BitmapFactory PIXEL DATA PIXEL DATA

  204. MarkableInputStream BitmapFactory inJustDecodeBounds=true ??? BitmapFactory java.io.IOException: Cannot reset at com.squareup.picasso.MarkableInputStream.reset(MarkableInputStream.java:99)

    at com.squareup.picasso.BitmapHunter.decodeStream(BitmapHunter.java:140) at com.squareup.picasso.BitmapHunter.hunt(BitmapHunter.java:217) at com.squareup.picasso.BitmapHunter.run(BitmapHunter.java:159) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:457) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) at java.lang.Thread.run(Thread.java:764) at com.squareup.picasso.Utils$PicassoThread.run(Utils.java:411)
  205. BitmapFactory MarkableInputStream InputStream BitmapFactory

  206. BitmapFactory MarkableInputStream InputStream Picasso 2.x BitmapFactory Picasso 3.x

  207. BitmapFactory MarkableInputStream InputStream Picasso 2.x BitmapFactory BufferedSource Picasso 3.x

  208. BitmapFactory MarkableInputStream InputStream Picasso 2.x BitmapFactory BufferedSource Picasso 3.x SourceBufferingInputStream

  209. BitmapFactory BufferedSource SourceBufferingInputStream

  210. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream

  211. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream offset: 0

  212. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC

    offset: 0
  213. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC

    offset: 0 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC 1024
  214. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC

    offset: 1024 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC 0
  215. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC

    offset: 1024 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC
  216. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC

    offset: 1024 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC
  217. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC

    offset: 1024 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC
  218. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC

    offset: 1024
  219. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream 2PIXEL DATA2 3PIXEL DATA3 4PIXEL DATA4

    1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC offset: 1024
  220. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream 2PIXEL DATA2 3PIXEL DATA3 4PIXEL DATA4

    1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC offset: 1024 2PIXEL DATA2 3PIXEL DATA3 4PIXEL DATA4 2048
  221. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream 2PIXEL DATA2 3PIXEL DATA3 4PIXEL DATA4

    1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC offset: 2048 2PIXEL DATA2 3PIXEL DATA3 4PIXEL DATA4 1024
  222. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream 2PIXEL DATA2 3PIXEL DATA3 4PIXEL DATA4

    1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC offset: 2048 2PIXEL DATA2 3PIXEL DATA3 4PIXEL DATA4
  223. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream 2PIXEL DATA2 3PIXEL DATA3 4PIXEL DATA4

    1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC offset: 2048
  224. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream 2PIXEL DATA2 3PIXEL DATA3 4PIXEL DATA4

    5PIXEL DATA5 6PIXEL DATA6 7PIXEL DATA7 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC offset: 2048
  225. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream 2PIXEL DATA2 3PIXEL DATA3 4PIXEL DATA4

    5PIXEL DATA5 6PIXEL DATA6 7PIXEL DATA7 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC offset: 2048 5PIXEL DATA5 6PIXEL DATA6 7PIXEL DATA7 3072
  226. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream 2PIXEL DATA2 3PIXEL DATA3 4PIXEL DATA4

    5PIXEL DATA5 6PIXEL DATA6 7PIXEL DATA7 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC offset: 3072 5PIXEL DATA5 6PIXEL DATA6 7PIXEL DATA7 2048
  227. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream 2PIXEL DATA2 3PIXEL DATA3 4PIXEL DATA4

    5PIXEL DATA5 6PIXEL DATA6 7PIXEL DATA7 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC offset: 3072 5PIXEL DATA5 6PIXEL DATA6 7PIXEL DATA7
  228. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream 2PIXEL DATA2 3PIXEL DATA3 4PIXEL DATA4

    5PIXEL DATA5 6PIXEL DATA6 7PIXEL DATA7 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC offset: 3072
  229. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream 2PIXEL DATA2 3PIXEL DATA3 4PIXEL DATA4

    5PIXEL DATA5 6PIXEL DATA6 7PIXEL DATA7 8PIXEL DATA8 9PIXEL DATA9 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC offset: 3072
  230. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream 2PIXEL DATA2 3PIXEL DATA3 4PIXEL DATA4

    5PIXEL DATA5 6PIXEL DATA6 7PIXEL DATA7 8PIXEL DATA8 9PIXEL DATA9 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC offset:x3072 8PIXEL DATA8 9PIXEL DATA9 3754
  231. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream 2PIXEL DATA2 3PIXEL DATA3 4PIXEL DATA4

    5PIXEL DATA5 6PIXEL DATA6 7PIXEL DATA7 8PIXEL DATA8 9PIXEL DATA9 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC offset: 3754 8PIXEL DATA8 9PIXEL DATA9 x3072
  232. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream 2PIXEL DATA2 3PIXEL DATA3 4PIXEL DATA4

    5PIXEL DATA5 6PIXEL DATA6 7PIXEL DATA7 8PIXEL DATA8 9PIXEL DATA9 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC offset: 3754 8PIXEL DATA8 9PIXEL DATA9
  233. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream 2PIXEL DATA2 3PIXEL DATA3 4PIXEL DATA4

    5PIXEL DATA5 6PIXEL DATA6 7PIXEL DATA7 8PIXEL DATA8 9PIXEL DATA9 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC offset: 3754
  234. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream 2PIXEL DATA2 3PIXEL DATA3 4PIXEL DATA4

    5PIXEL DATA5 6PIXEL DATA6 7PIXEL DATA7 8PIXEL DATA8 9PIXEL DATA9 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC offset: 3754 ???
  235. BufferedSource 2PIXEL DATA2 3PIXEL DATA3 4PIXEL DATA4 5PIXEL DATA5 6PIXEL

    DATA6 7PIXEL DATA7 8PIXEL DATA8 9PIXEL DATA9 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC offset: 3754 ??? BitmapFactory inJustDecodeBounds=true SourceBufferingInputStream
  236. BitmapFactory InputStream BufferedSource 2PIXEL DATA2 3PIXEL DATA3 4PIXEL DATA4 5PIXEL

    DATA5 6PIXEL DATA6 7PIXEL DATA7 8PIXEL DATA8 9PIXEL DATA9 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC BitmapFactory inJustDecodeBounds=true SourceBufferingInputStream
  237. BitmapFactory InputStream BufferedSource 2PIXEL DATA2 3PIXEL DATA3 4PIXEL DATA4 5PIXEL

    DATA5 6PIXEL DATA6 7PIXEL DATA7 8PIXEL DATA8 9PIXEL DATA9 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC BitmapFactory inJustDecodeBounds=true SourceBufferingInputStream
  238. BitmapFactory InputStream BufferedSource 2PIXEL DATA2 3PIXEL DATA3 4PIXEL DATA4 5PIXEL

    DATA5 6PIXEL DATA6 7PIXEL DATA7 8PIXEL DATA8 9PIXEL DATA9 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC BitmapFactory inJustDecodeBounds=true SourceBufferingInputStream
  239. BitmapFactory InputStream BufferedSource 2PIXEL DATA2 3PIXEL DATA3 4PIXEL DATA4 5PIXEL

    DATA5 6PIXEL DATA6 7PIXEL DATA7 8PIXEL DATA8 9PIXEL DATA9 BitmapFactory inJustDecodeBounds=true SourceBufferingInputStream
  240. BitmapFactory InputStream BufferedSource 5PIXEL DATA5 6PIXEL DATA6 7PIXEL DATA7 8PIXEL

    DATA8 9PIXEL DATA9 BitmapFactory inJustDecodeBounds=true SourceBufferingInputStream
  241. BitmapFactory InputStream BufferedSource 8PIXEL DATA8 9PIXEL DATA9 BitmapFactory inJustDecodeBounds=true SourceBufferingInputStream

  242. BitmapFactory InputStream BufferedSource BitmapFactory inJustDecodeBounds=true SourceBufferingInputStream

  243. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream offset: 0

  244. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream 1METADATA1 MAGIC offset: 0

  245. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream 1METADATA1 MAGIC offset: 341 1METADATA1 MAGIC

  246. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream 1METADATA1 MAGIC offset: 341 1METADATA1 MAGIC

  247. BitmapFactory inJustDecodeBounds=true BufferedSource SourceBufferingInputStream 1METADATA1 MAGIC offset: 341 1METADATA1 MAGIC

    1920x1080
  248. BufferedSource 1METADATA1 MAGIC 1METADATA1 MAGIC offset: 341 BitmapFactory inJustDecodeBounds=true SourceBufferingInputStream

    1920x1080
  249. ExifInterface BufferedSource SourceBufferingInputStream 1METADATA1 MAGIC 1METADATA1 MAGIC offset: 341 BitmapFactory

    inJustDecodeBounds=true SourceBufferingInputStream 1920x1080 offset: 0
  250. ExifInterface BufferedSource SourceBufferingInputStream 1METADATA1 MAGIC 1METADATA1 MAGIC offset: 341 BitmapFactory

    inJustDecodeBounds=true SourceBufferingInputStream 1920x1080 offset: 341 1METADATA1 MAGIC
  251. ExifInterface BufferedSource SourceBufferingInputStream 1METADATA1 MAGIC 1METADATA1 MAGIC offset: 341 BitmapFactory

    inJustDecodeBounds=true SourceBufferingInputStream 1920x1080 offset: 341 1METADATA1 MAGIC
  252. ExifInterface BufferedSource SourceBufferingInputStream 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC 1METADATA1

    MAGIC offset: 341 BitmapFactory inJustDecodeBounds=true SourceBufferingInputStream 1920x1080 offset: 341
  253. ExifInterface BufferedSource SourceBufferingInputStream 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC 1METADATA1

    MAGIC offset: 341 BitmapFactory inJustDecodeBounds=true SourceBufferingInputStream 1920x1080 offset: 1024 1PIXEL DATA1 3METADATA3 2METADATA2 341
  254. ExifInterface BufferedSource SourceBufferingInputStream 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC 1METADATA1

    MAGIC offset: 341 BitmapFactory inJustDecodeBounds=true SourceBufferingInputStream 1920x1080 offset: 1024 1PIXEL DATA1 3METADATA3 2METADATA2 341
  255. ExifInterface BufferedSource SourceBufferingInputStream 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC 1METADATA1

    MAGIC offset: 341 BitmapFactory inJustDecodeBounds=true SourceBufferingInputStream 1920x1080 offset: 1024 1PIXEL DATA1 3METADATA3 2METADATA2 341 90°
  256. BufferedSource 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC 1METADATA1 MAGIC offset:

    341 BitmapFactory inJustDecodeBounds=true SourceBufferingInputStream 1920x1080 offset: 1024 1PIXEL DATA1 3METADATA3 2METADATA2 341 90° ExifInterface SourceBufferingInputStream
  257. BitmapFactory InputStream BufferedSource 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC 1METADATA1

    MAGIC offset: 341 BitmapFactory inJustDecodeBounds=true SourceBufferingInputStream 1920x1080 offset: 1024 1PIXEL DATA1 3METADATA3 2METADATA2 341 90° ExifInterface SourceBufferingInputStream
  258. BitmapFactory InputStream BufferedSource 2PIXEL DATA2 3PIXEL DATA3 4PIXEL DATA4 1PIXEL

    DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC 1METADATA1 MAGIC offset: 341 BitmapFactory inJustDecodeBounds=true SourceBufferingInputStream 1920x1080 offset: 1024 1PIXEL DATA1 3METADATA3 2METADATA2 341 90° ExifInterface SourceBufferingInputStream
  259. BitmapFactory InputStream BufferedSource 2PIXEL DATA2 3PIXEL DATA3 4PIXEL DATA4 5PIXEL

    DATA5 6PIXEL DATA6 7PIXEL DATA7 1PIXEL DATA1 3METADATA3 2METADATA2 1METADATA1 MAGIC 1METADATA1 MAGIC offset: 341 BitmapFactory inJustDecodeBounds=true SourceBufferingInputStream 1920x1080 offset: 1024 1PIXEL DATA1 3METADATA3 2METADATA2 341 90° ExifInterface SourceBufferingInputStream
  260. BitmapFactory InputStream BufferedSource 2PIXEL DATA2 3PIXEL DATA3 4PIXEL DATA4 5PIXEL

    DATA5 6PIXEL DATA6 7PIXEL DATA7 8PIXEL DATA8 9PIXEL DATA9 1METADATA1 MAGIC offset: 341 BitmapFactory inJustDecodeBounds=true SourceBufferingInputStream 1920x1080 offset: 1024 1PIXEL DATA1 3METADATA3 2METADATA2 341 90° ExifInterface SourceBufferingInputStream
  261. BitmapFactory InputStream BufferedSource 5PIXEL DATA5 6PIXEL DATA6 7PIXEL DATA7 8PIXEL

    DATA8 9PIXEL DATA9 1METADATA1 MAGIC offset: 341 BitmapFactory inJustDecodeBounds=true SourceBufferingInputStream 1920x1080 offset: 1024 1PIXEL DATA1 3METADATA3 2METADATA2 341 90° ExifInterface SourceBufferingInputStream
  262. BitmapFactory InputStream BufferedSource 8PIXEL DATA8 9PIXEL DATA9 1METADATA1 MAGIC offset:

    341 BitmapFactory inJustDecodeBounds=true SourceBufferingInputStream 1920x1080 offset: 1024 1PIXEL DATA1 3METADATA3 2METADATA2 341 90° ExifInterface SourceBufferingInputStream
  263. BitmapFactory InputStream BufferedSource 1METADATA1 MAGIC offset: 341 BitmapFactory inJustDecodeBounds=true SourceBufferingInputStream

    1920x1080 offset: 1024 1PIXEL DATA1 3METADATA3 2METADATA2 341 90° ExifInterface SourceBufferingInputStream
  264. BitmapFactory InputStream BufferedSource 1METADATA1 MAGIC offset: 341 BitmapFactory inJustDecodeBounds=true SourceBufferingInputStream

    1920x1080 offset: 1024 1PIXEL DATA1 3METADATA3 2METADATA2 341 90° ExifInterface SourceBufferingInputStream
  265. • Android P • Improvements • OkHttp 2.x => 3.x


    • Okio integration 3.x Goals
  266. Picasso.with(context)X .load(url) .placeholder(R.drawable.placeholder) .error(R.drawable.error) .fit() .into(view);

  267. PicassoProvider.get()X .load(url) .placeholder(R.drawable.placeholder) .error(R.drawable.error) .fit() .into(view); with context

  268. picasso.load(url) .placeholder(R.drawable.placeholder) .error(R.drawable.error) .fit() .into(view);

  269. abstract class RequestHandler { abstract boolean canHandleRequest(Request request); abstract Result

    load(Request request, int networkPolicy); }X
  270. abstract class RequestHandler { abstract boolean canHandleRequest(Request request); abstract void

    load(Picasso picasso, Request request, Callback callback); }X Result int networkPolicy
  271. • Better separation of concerns: Image/Target/RenderCall Coming Soon

  272. • Better separation of concerns: Image/Target/RenderCall • Propagating Drawables to

    Target (animated GIFs!) Coming Soon
  273. • Better separation of concerns: Image/Target/RenderCall • Propagating Drawables to

    Target (animated GIFs!) • Improved pipelining Coming Soon
  274. • Better separation of concerns: Image/Target/RenderCall • Propagating Drawables to

    Target (animated GIFs!) • Improved pipelining • More? Let us know! Coming Soon
  275. Rinsing the Brush: Picasso 3.0 @jrodbx @JakeWharton

  276. PICASSO WILL RETURN 3.0