Hi, I just came across this where we are extending...
# android
p
Hi, I just came across this where we are extending context with a toast function: https://github.com/android/android-ktx/pull/290 The call to toast becomes a lot nicer because we can just do
toast(...)
without worrying about
show()
etc My issue is whether this is actually a form of abuse on the extension function mechanism because Toast is not really an extension of context. Similarly, I have come across several examples where extension functions have been used to simply shave off a parameter from the original method call. Any opinions?
m
IMAO this method should be called showToast() just to make it clear what it actually does
👍 2
p
Possibly but I am more concerned about whether extending Context is the right thing to do because extension functions were originally meant to augment/enhance a class and in this example it looks like Context and Toast are not related
m
I see your point here. But this extension actually is helpful 🙂
p
I totally agree! The end result is lovely but it feels controversial
l
seems more like a problem of the
Context
itself being required for everything… but since we have this god object, makes sense these extensions for this context
m
exactly:) It’s how android works:)
g
I don't think that this is abuse and I don't think that this extension is controversial. It's completely valid and convenient way to use extensions. To bring some additions features to particular scope
In this case scope of context. Context also has a lot of things, for example resources, and I don't see any particular reason why toast shouldn't be used as extension for context
p
Hmm ok
And how about this one:
Copy code
fun Context.loadImageCenterCrop(url: String, imageView: ImageView) {
  Picasso.withContext(this)
    .load(url)
    .centerCrop()
    .fit()
    .into(imageView)
}

// Elsewhere
context.loadImageCenterCrop("<http://example.com/image.jpg>", myImageView)
m
Why not do that on ImageView?:)
l
this could be an extension of the imageView itself and would be better to get the context from the imageView
2
p
Yes exactly! A better way is this
Copy code
fun ImageView.loadImageCenterCrop(url: String) {
  Picasso.withContext(this.getContext())
    .load(url)
    .centerCrop()
    .fit()
    .into(this)
}
Hence why I got a bit uneasy on things that extend Context
l
yes, but with the
toast
would be weird making an extension of
String
m
We do that this way:
Copy code
fun ImageView.picassoLoad(url: String, callback: ((requestCreator: RequestCreator) -> Unit)? = null) {
    this.context.picasso.load(url).apply {
        callback?.invoke(this)
    }.into(this)
}
👍 2
and yes… picasso is added to context:D
😂 1
j
I get the context from the imageView, if that makes sense
👍 1
1
m
me too.. picasso is added to context which is inside view:)
p
Yea definitely. That’s like in the second example I showed where I am extending ImageView instead 🙂 But saying that, the first example is still an extension function but used in the wrong way
My point was that even though both
Copy code
fun Context.loadImageCenterCrop(url: String, imageView: ImageView) {
  Picasso.withContext(this)
    .load(url)
    .centerCrop()
    .fit()
    .into(imageView)
}

// Elsewhere
context.loadImageCenterCrop("<http://example.com/image.jpg>", myImageView)
and
Copy code
fun ImageView.loadImageCenterCrop(url: String) {
  Picasso.withContext(this.getContext())
    .load(url)
    .centerCrop()
    .fit()
    .into(this)
}
both make your code more concise and both use the extension function mechanism, the first approach is bad because context has nothing to do with
loadImageCenterCrop
m
yea, i just use:
Copy code
val Context.picasso: Picasso
    get() = Picasso.with(this)
Context works as service locator anyway, so no harm done here:)
g
Don't like this solution, also you create an instance of Picasso for each call
m
It does not. We’ve used Picasso.setSingletonInstance() in application, and this method is just returning this instance
g
Okay, I see
Copy code
toast("Hi there!")
toast(R.string.message)
longToast("Wow, such duration")
👍 1
p
Thanks all for your input 👍 So I guess the conclusion is that for
Toast
it is fine to extend
Context
because it is like bringing new additions to the scope and it is convenient but in the case of
Copy code
fun Context.loadImageCenterCrop(url: String, imageView: ImageView) {
  Picasso.withContext(this)
    .load(url)
    .centerCrop()
    .fit()
    .into(imageView)
}
Even though essentially, it is doing the same thing as extending
Context
with
Toast
, it is not fine because it is better to extend
ImageView
?
g
Yes, also each view already contains context, no need to pass context and ImageView separately. Also it's just looks more natural to have such method on imageView