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

Experiment with alternate delayed size resolution #2292

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions picasso/src/main/java/com/squareup/picasso3/Picasso.kt
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ class Picasso internal constructor(
@get:JvmName("-targetToDeferredRequestCreator")
internal val targetToDeferredRequestCreator = mutableMapOf<ImageView, DeferredRequestCreator>()

private val targetToSizeResolver = mutableMapOf<Any, SizeResolver>()

@get:JvmName("-shutdown")
@set:JvmName("-shutdown")
internal var shutdown = false
Expand Down Expand Up @@ -135,6 +137,11 @@ class Picasso internal constructor(
for (i in deferredRequestCreators.indices) {
deferredRequestCreators[i].cancel()
}

val sizeResolvers = targetToSizeResolver.values.toList()
for (i in sizeResolvers.indices) {
sizeResolvers[i].onCancel()
}
}

/** Cancel any existing requests for the specified target [ImageView]. */
Expand Down Expand Up @@ -181,6 +188,10 @@ class Picasso internal constructor(
deferredRequestCreator.cancel()
}
}

targetToSizeResolver.values.forEach { sizeResolver ->
// TODO: Work out how to cancel size resolvers by tag.
}
}

@OnLifecycleEvent(ON_STOP)
Expand All @@ -200,6 +211,8 @@ class Picasso internal constructor(
dispatcher.dispatchPauseTag(tag)
}
}

// TODO: Work how to to pause size resolvers.
}

/**
Expand Down Expand Up @@ -230,6 +243,8 @@ class Picasso internal constructor(
dispatcher.dispatchResumeTag(tag)
}
}

// TODO: Work out how to resume size resolvers.
}

/**
Expand Down Expand Up @@ -386,6 +401,14 @@ class Picasso internal constructor(
return nextRequest
}

internal fun resolveSize(sizeResolver: SizeResolver, target: Any, callback: (Size) -> Unit) {
if (targetToSizeResolver.containsKey(target)) {
cancelExistingRequest(target)
}
targetToSizeResolver[target] = sizeResolver
sizeResolver.resolve(callback)
}

@JvmName("-defer")
internal fun defer(view: ImageView, request: DeferredRequestCreator) {
// If there is already a deferred request, cancel it.
Expand Down Expand Up @@ -517,6 +540,7 @@ class Picasso internal constructor(
action.cancel()
dispatcher.dispatchCancel(action)
}
targetToSizeResolver.remove(target)
if (target is ImageView) {
val deferredRequestCreator = targetToDeferredRequestCreator.remove(target)
deferredRequestCreator?.cancel()
Expand Down
27 changes: 26 additions & 1 deletion picasso/src/main/java/com/squareup/picasso3/RequestCreator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class RequestCreator internal constructor(
@DrawableRes private var errorResId = 0
private var placeholderDrawable: Drawable? = null
private var errorDrawable: Drawable? = null
private var sizeResolver: SizeResolver? = null

/** Internal use only. Used by [DeferredRequestCreator]. */
@get:JvmName("-tag")
Expand All @@ -68,6 +69,12 @@ class RequestCreator internal constructor(
check(!picasso.shutdown) { "Picasso instance already shut down. Cannot submit new requests." }
}

fun sizeResolver(sizeResolver: SizeResolver): RequestCreator {
check(!deferred) { "Use only one of fit() or sizeResolver()." }
this.sizeResolver = sizeResolver
return this
}

/**
* Explicitly opt-out to having a placeholder set when calling [into].
*
Expand Down Expand Up @@ -433,6 +440,17 @@ class RequestCreator internal constructor(
return
}

if (sizeResolver != null) {
picasso.resolveSize(sizeResolver!!, target) { (width, height) ->
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Deferred size resolution for BitmapTarget

resize(width, height)
loadIntoTarget(target, started)
}
} else {
loadIntoTarget(target, started)
}
}

private fun loadIntoTarget(target: BitmapTarget, started: Long) {
val request = createRequest(started)
if (shouldReadFromMemoryCache(request.memoryPolicy)) {
val bitmap = picasso.quickMemoryCacheCheck(request.key)
Expand Down Expand Up @@ -556,11 +574,18 @@ class RequestCreator internal constructor(
setPlaceholder(target, getPlaceholderDrawable())
}
picasso.defer(target, DeferredRequestCreator(this, target, callback))
picasso.resolveSize(ViewSizeResolver(target), target) { (width, height) ->
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Adapting for existing fit()

data.resize(width, height)
loadIntoImageView(target, started, callback)
}
return
}
data.resize(width, height)
}

loadIntoImageView(target, started, callback)
}

private fun loadIntoImageView(target: ImageView, started: Long, callback: Callback? = null) {
val request = createRequest(started)

if (shouldReadFromMemoryCache(request.memoryPolicy)) {
Expand Down
74 changes: 74 additions & 0 deletions picasso/src/main/java/com/squareup/picasso3/ViewSizeResolver.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.squareup.picasso3

import android.view.View
import android.view.ViewTreeObserver
import androidx.annotation.Px

interface SizeResolver {
fun resolve(listener: (Size) -> Unit)
fun onCancel()
}

data class Size(@Px val width: Int, @Px val height: Int)

class ViewSizeResolver(
private val target: View,
) : SizeResolver, ViewTreeObserver.OnPreDrawListener, View.OnAttachStateChangeListener {

private var listener: ((Size) -> Unit)? = null

override fun resolve(listener: (Size) -> Unit) {
val startingWidth = target.width
val startingHeight = target.height

if (startingWidth > 0 && startingHeight > 0) {
listener(Size(startingWidth, startingHeight))
return
}

this.listener = listener
target.addOnAttachStateChangeListener(this)
// Only add the pre-draw listener if the view is already attached.
// See: https://github.com/square/picasso/issues/1321
if (target.windowToken != null) {
onViewAttachedToWindow(target)
}
}

override fun onCancel() {
listener = null
target.removeOnAttachStateChangeListener(this)
val vto = target.viewTreeObserver
if (vto.isAlive) {
vto.removeOnPreDrawListener(this)
}
}

override fun onPreDraw(): Boolean {
val vto = target.viewTreeObserver
if (!vto.isAlive) {
return true
}

val width = target.width
val height = target.height

if (width <= 0 || height <= 0) {
return true
}

target.removeOnAttachStateChangeListener(this)
vto.removeOnPreDrawListener(this)
listener?.invoke(Size(width, height))
listener = null
return true
}

override fun onViewAttachedToWindow(view: View) {
view.viewTreeObserver.addOnPreDrawListener(this)
}

override fun onViewDetachedFromWindow(view: View) {
view.viewTreeObserver.removeOnPreDrawListener(this)
}
}