Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: Switch to just speak Call.Factory #8

Merged
merged 9 commits into from
Aug 19, 2019
Merged

Proposal: Switch to just speak Call.Factory #8

merged 9 commits into from
Aug 19, 2019

Conversation

ZacSweers
Copy link
Contributor

@ZacSweers ZacSweers commented Aug 13, 2019

This is a proposal PR that switches the ImageLoaderBuilder + internals to just speak Call.Factory. This is similar to how Retrofit handles it, and allows for consumers to provide their own implementations of Call.Factory.

Two primary examples:

  • A clever technique to improve startup perf is to lazily instantiate the OkHttpClient stack (instance + cache) by deferring its construction until the first network call. This way, construction is done off the main thread. I demoed this in c03e7c2, and can revert 69ca796 if you want to keep that in the sample.
  • Some apps provide entirely different network implementations behind Call.Factory, using the interface to allow them to interop with popular libraries like Retrofit still. This would enable those as well.

In order to sanely support this, I think the builder helper method didn't have a place, and instead made the logic for applying those configurations available via public helper extension function. This way consumers can use it in their own construction, and also better supports sharing connection pools between instances. If clients want to use the optimized configuration, they can just call newBuilder() on their existing instance to share the connection pool while gettin the optimized configuration for a new instance ultimately provided into callFactory.

@ZacSweers
Copy link
Contributor Author

ZacSweers commented Aug 13, 2019

Quick note: for those who don't know - OkHttpClient is an implementation of Call.Factory, so clients can be passed directly as well via callFactory(client). Retrofit exposes both callFactory(OkHttpClient) and callFactory(Call.Factory), where the former is just a shorthand for the latter. I've pinged them to ask why they offer both and will update if there's an added advantage to it 👍

@colinrtwhite
Copy link
Member

I really like the idea of using Call.Factory. A few thoughts:

  • We should keep the okHttpClient(OkHttpClient) method, but also provide a callFactory(CallFactory) method similar to how Retrofit handles it. This helps with discovery.
  • I'm not a huge fan of applyCoilOptimizations. I think I would prefer to keep okHttpClient(builder: OkHttpClient.Builder.() -> Unit) and only apply the optimizations in the case where a user doesn't set a client or call factory. If the user sets an OkHttpClient builder, I'd apply the optimizations there as well.

^ This doesn't cover the case where a user lazy inits the OkHttpClient, but still wants Coil's default OkHttpClient configuration. Maybe it would make sense to make a public Utils method for that? What do you think?

@ZacSweers
Copy link
Contributor Author

ZacSweers commented Aug 14, 2019

We should keep the okHttpClient(OkHttpClient) method, but also provide a callFactory(CallFactory) method similar to how Retrofit handles it. This helps with discovery.

Agreed, confirmed this is why Retrofit does it as well 👍

Maybe it would make sense to make a public Utils method for that? What do you think?

Yep I'd agree with that. That was the idea behind extracting it to the function. I do think it should be one or the other though. Trying to balance all of them together would create confusing API imo, as it'd have okHttpClient(), callFactory(), and okHttpClient(Builder.()) where they all have different implications/behavior. Applying the builder onto the directly-handed OkHttpClient also seems potentially problematic if the user is trying to limit the behavior of the client they pass in. What do you think?

@colinrtwhite
Copy link
Member

I think you're right that okHttpClient(Builder.()) should be removed as it has behaviour that the other two methods don't, which can be confusing. Going to think about this a little more since ideally I'd like to avoid a Utils method since it's not super discoverable.

I'm likely going to ship 0.6.1 tomorrow, but the conversion to Call.Factory would be a good candidate for 0.7.0.

@ZacSweers
Copy link
Contributor Author

Sounds good, just let me know 👍

private var okHttpClient: OkHttpClient? = null
private var okHttpClientBuilder: (OkHttpClient.Builder.() -> Unit)? = null
private var callFactory: Call.Factory? = null
private var canRebuildWithOptimizations: Boolean = false
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove canRebuildWithOptimizations since we should only apply these optimizations if we need to build the default call factory.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By happy coincidence, I forgot to wire this up anywhere. Just had to delete the field. 34b0090

*/
fun okHttpClient(client: OkHttpClient) = apply {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep this (but remove okHttpClientBuilder) for discoverability.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/**
* Applies the preferred optimizations for Coil (image loading library) to this given Builder instance.
*/
fun OkHttpClient.Builder.applyCoilOptimizations(context: Context): OkHttpClient.Builder = apply {
Copy link
Member

@colinrtwhite colinrtwhite Aug 19, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you move this into Utils, set Utils to public, and set every other method to internal? I'd also change the name to applyOkHttpClientOptimizations. Thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@colinrtwhite
Copy link
Member

colinrtwhite commented Aug 19, 2019

@ZacSweers Left a few comments. Still not 100% sure on having a Utils method to apply the optimizations, but I wanted to avoid delaying this PR more.

Also can you rebase/merge in master to have tests run? Thanks!

@ZacSweers
Copy link
Contributor Author

Done and rebased

/**
* [OkHttpClient] utilities for Coil.
*/
object OkHttpClients {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you remove this + make applyCoilOptimizations a top level function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 9384a04

@@ -0,0 +1,28 @@
package coil.util
Copy link
Member

@colinrtwhite colinrtwhite Aug 19, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@file:JvmName("OkHttpClients")

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 9384a04

Copy link
Member

@colinrtwhite colinrtwhite left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯

@colinrtwhite colinrtwhite merged commit 9c3810b into coil-kt:master Aug 19, 2019
@ZacSweers ZacSweers deleted the z/callFactory branch August 19, 2019 23:08
@iNoles iNoles mentioned this pull request Jul 5, 2020
4 tasks
colinrtwhite pushed a commit that referenced this pull request Oct 5, 2022
* Switch internals to use Call.Factory interface

* Update ImageLoaderBuilder to just accept a Call.Factory

* Update sample demonstrating deferred init

* Simplify sample

* Move applyOkHttpClientOptimizations to Utils with new name

* Add back okHttpClient()

* Remove unused canRebuildWithOptimizations property

* Extract OkHttpClients util and revert changes in Utils.kt

* Make applyCoilOptimizations top level w/ file name
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants