-
Notifications
You must be signed in to change notification settings - Fork 670
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
Adds support for generic Uri strings. #32
Conversation
FYI the test script failed, but it failed on Master in the same place (TimeoutException after socket closed in integration tests), so I've submitted anyway (as there is no difference between master and my branch in the test report). |
Thanks! Will take a look at this after pushing |
|
||
internal class HttpStringMapper : Mapper<String, HttpUrl> { | ||
|
||
override fun handles(data: String): Boolean = HttpUrl.parse(data) != null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have benchmarks to verify this, but I believe this adds a non-zero amount of overhead to every String URL request since we end up calling HttpUrl.get
twice. Mappers are also called on the main thread so they need to be fast + non-blocking.
Instead of having two separate mappers, I think my preferred way to implement this would be something like this: class StringMapper : Mapper<String, Any> {
override fun map(data: String): Any {
val uri = Uri.parse(data)
val scheme = checkNotNull(data.scheme) { "Invalid Uri/URL. Missing scheme." }
return if (scheme == "http" || scheme == "https") {
HttpUrl.get(data)
} else {
uri
}
}
} Still not sure if it's best to treat |
Re the alternative approach: I originally had Also if you rebase/merge in master tests should pass. |
I'd like to push back on the Does a While you're correct that the overhead to call So without implementing the An alternative approach that would allow for improved performance, while keeping mappers focused on single source -> destination processes could be to update the Mapper interface to remove the interface Mapper<T : Any, V : Any> {
/**
* Convert [data] into [V], or return null.
*/
fun map(data: T): V?
} This provides the same information as the previous API, but means that each mapper that matches the type only has to attempt to decode the source a single time, instead of the current architecture which requires two decodes. The updated class StringHttpUrlMapper : Mapper<String, HttpUrl> {
override fun map(data: String): HttpUrl? = HttpUrl.get(data)
} The call-site to get the mapped data also becomes simplified, and quite performant when using Kotlin Sequences. mappers.asSequence()
.filter { it.type.isAssignableFrom(data::class.java) }
.mapNotNull { (it.converter as Mapper<Any, *>).map(data) }
.firstOrNull() I realize this would be an API change, but it could help simplify and improve performance, while reducing the need to have single God Mappers. Thoughts? |
@rharter Hey sorry for the late response on this - wanted to think through your suggestion for a couple days. I don't think I want to remove With Retrofit, Converter.Factory instances either return null or a |
For |
Sorry for the silence on this, I've been travelling for conferences and family. I'll circle back here this coming week. |
Fixes #24
Changes
I added a generic
UriStringMapper
to handle generic strings. It is intentionally added at the end of the mappers in theRealImageLoader
so thatHttpStringMapper
is preferred. I also updated theStringMapper
to only handle strings supported byHttpUrl
instead of throwing an exception.Alternative
In the process of implementing this I realized that there could be an alternative approach that might be more flexible, but could come with a performance/complexity overhead. Since there is already a
Mapper<Uri, HttpUrl>
, the data mapping could be updated to continue mapping data until there are no more mappers that can handle the data.This would result in a url string going
String > Uri > HttpUrl
and a file string goingString > Uri
, but would also probably require more code to handle cases like map cycles and could result in a very long conversion route in extreme cases.Because that's a larger change, I decided to simply implement the simple approach for this PR.