How Picasso gets the Context without parameter passing
What’s new?
I’ve updated the Picasso library recently and mainly see if anything new and surprising. The second goal was to see if the latest version has some bug fixes. I didn’t realize that, on the latest version 2.7828
, it changes the way to instantiate the Picasso instance by using the With(Context context).
Instead, it uses a Get()
function to get the instance:
1 | Picasso.get() |
How does it do?
That’s interesting. Here comes a question: how does the Get()
create a Picasso instance without getting any Application/Activity context? Any magic inside? So, I dive into the source code a little bit to reveal the secrete. Here is the source code of the Picasso Get()
:
1 | public static Picasso get() { |
Alright, you can find this code piece:
1 | if (PicassoProvider.context == null) { |
Is this PicassoProvider the same thing as ContentProvider
? Let’s take a look at the source code of picasso/PicassoProvider.java
1 | @RestrictTo(LIBRARY) |
That’s right. It’s a content provider. But you can see this content provider doesn’t function. Just several overridden functions. Let’s check the AndroidManifest.xml:
1 | <manifest xmlns:android="http://schemas.android.com/apk/res/android" |
It’s there but doesn’t use any keyword like export
to outside users.
The tricky part.
There’s a tricky part here. If you notice the authorities’ declaration of the content provider, you can see that it uses the ${applicationId}
this way to set up a sole authority for different Apps. That’s because if you set up a unique authority, then that’s only one application running on the device can use this library at the same time. So, by using this way, you can create a general 3rd library for different Apps. You should also remember to remove the ApplicationId
setting in the library module, or the Gradle will automatically use this ApplicationId
from build.gradle file.
Another question is: how can we make sure the content provider would be the first component to initialize? That’s because when an Android application has launched, there is a well-defined order of initializing components:
Each content provider declared in the manifest would be initialized first in this order
The application would be the second part to initialize.
The final one would be the component that’s invoked by some intent.
That’s the reason why Picasso can use this way to get the context first at the very beginning of the App launching.
But I think Picasso will use another way to instantiate the instance cause it shows the Builder
class in the latest master branch.
1 | /** Fluent API for creating {@link Picasso} instances. */ |
You will need to use the Builder
class and pass in the Application/Activity context to initialize the Builder. And then it also removes the declaration of PicassoProvider
in the AndroidManifest.xml
:
1 | <manifest package="com.squareup.picasso3"/> |
The future
Why Picasso wants to deprecate this way? In the Picasso.java
, it shows this:
1 | /** |
It should be reasonable to have an Activity context with Lifecycle management. That might be the reason why it obsoletes the way it’s using now.