square / picasso

A powerful image downloading and caching library for Android
https://square.github.io/picasso/
Apache License 2.0
18.71k stars 3.97k forks source link

Expecting images to load faster than they currently are - Am I misusing Picasso? #1923

Closed ColtonIdle closed 6 years ago

ColtonIdle commented 6 years ago

I would like to preface that I've read a bunch of SO posts and looked through a bit of the code and I just find myself scratching my head with Picasso.

I have a single requirement/assumption about Picasso. Picasso will load images instantly if they have been downloaded before (disk/ram cache).

My sample app consists of:

class CustomApp : Application() {
    override fun onCreate() {
        super.onCreate()
        val picasso = Picasso.Builder(applicationContext)
                .build()
        picasso.setIndicatorsEnabled(true)
        picasso.isLoggingEnabled = true
        Picasso.setSingletonInstance(picasso)
    }
}
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        Picasso.with(this).load("http://i.imgur.com/DvpvklR.png").placeholder(R.drawable.ic_launcher_foreground).into(imageView)
        imageView.setOnClickListener { startActivity(Intent(application, Main2Activity::class.java)) }
    }
}
class Main2Activity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main2)
        Picasso.with(this).load("https://images.unsplash.com/photo-1495965478447-052a41235743?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=ca957400c4e58a60e146eaaf0da399a8&auto=format&fit=crop&w=1561&q=80").placeholder(R.drawable.ic_launcher_foreground).into(imageView)
    }
}
  1. When I open up the app for the first time, I see the placeholder, then an image with a red tag. EXPECTED
  2. When I click on the image to go to the next activity, I see the placeholder with a red tag. EXPECTED
  3. Click back, image is there instantly with the red tag. The activity never went away, so this makes sense. EXPECTED
  4. Click on the image to go to next activity. Image is there instantly with green tag. EXPECTED.
  5. Hit back twice to return to launcher. Click app icon. First image appears instantly with green tag. EXPECTED
  6. Click the image to go to next activity. Image loads instantly with green tag. EXPECTED.
  7. Open recents. Swipe the app away. Reopen. See the placeholder flash. Then image loads with blue tag. Kinda expected. Would hope to not see the placeholder at all.
  8. Click to go to next activity and see the placeholder for a good 300ms. Not fast enough. Would expect it to be instantly there.

Is 7 and 8 unreasonable?

The reason I want them to be instant is that we're going through an initiative to essentially offload all bitmaps to the web and not ship them with the app for lighter apks. These images will never have their URLs changed. Right now we are definitely stress testing with full bleed images before we introduce thumbor, but even before we do so it makes sense that if I cram any images into the apk, they load "instantly" in onCreate and are there right when the user sees the activity, but not with picasso. I feel like I'm missing something.

JakeWharton commented 6 years ago

Images are batched in 180ms chunks to the main thread after decode. If you enable logging you will see a summary of the internal events which result in the image being delivered to the main thread. The first image load will also be subject to HTTP client initialization and thread creation which will slow things down. 300ms sounds about normal.

On master we've removed the batching, but it still isn't going to ever be instant because it has to roundtrip through a background thread, initialize the HTTP client, perform the decode, and perform any transformations.

ColtonIdle commented 6 years ago

@JakeWharton so there's no magical caching strategy or something that I'm missing?

Is there anyway to get this to be synchronous by chance? I sold my PMs on the idea of offloading images to the web for smaller apk, then they only ever need to be downloaded once, and they will act like natively packaged images, but my PM called me out on the placeholder image being present for a short period and said how natively packaged images don't do that.

JakeWharton commented 6 years ago

You can invoke Picasso synchronously or request the image synchronously using OkHttp directly but I wouldn't recommend it as you're going to block the main thread during app startup and create an unresponsive experience.

ColtonIdle commented 6 years ago

Thanks @JakeWharton I'll try a few things out and see how they end up. Feel free to close this issue.

jlubeck commented 5 years ago

Hey @ColtonIdle, did you come up with a solution to this? I'm running into the exact same problem. I have my PMs on my back complaining how our iOS counterpart is displaying cached images instantly, and we are not. Would appreciate any input on how to improve this if possible!