https://kotlinlang.org logo
#android
Title
# android
p

Pascal How

03/06/2018, 10:54 AM
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

miszmaniac

03/06/2018, 11:02 AM
IMAO this method should be called showToast() just to make it clear what it actually does
👍 2
p

Pascal How

03/06/2018, 11:06 AM
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

miszmaniac

03/06/2018, 11:07 AM
I see your point here. But this extension actually is helpful 🙂
p

Pascal How

03/06/2018, 11:07 AM
I totally agree! The end result is lovely but it feels controversial
l

leosan

03/06/2018, 11:16 AM
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

miszmaniac

03/06/2018, 11:16 AM
exactly:) It’s how android works:)
g

gildor

03/06/2018, 11:17 AM
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

Pascal How

03/06/2018, 11:23 AM
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

miszmaniac

03/06/2018, 11:26 AM
Why not do that on ImageView?:)
l

leosan

03/06/2018, 11:26 AM
this could be an extension of the imageView itself and would be better to get the context from the imageView
2
p

Pascal How

03/06/2018, 11:26 AM
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

leosan

03/06/2018, 11:27 AM
yes, but with the
toast
would be weird making an extension of
String
m

miszmaniac

03/06/2018, 11:27 AM
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

julioyg

03/06/2018, 1:50 PM
I get the context from the imageView, if that makes sense
👍 1
1
m

miszmaniac

03/06/2018, 1:51 PM
me too.. picasso is added to context which is inside view:)
p

Pascal How

03/06/2018, 1:55 PM
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

miszmaniac

03/06/2018, 2:02 PM
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

gildor

03/06/2018, 2:04 PM
Don't like this solution, also you create an instance of Picasso for each call
m

miszmaniac

03/06/2018, 2:17 PM
It does not. We’ve used Picasso.setSingletonInstance() in application, and this method is just returning this instance
g

gildor

03/07/2018, 1:03 AM
Okay, I see
Copy code
toast("Hi there!")
toast(R.string.message)
longToast("Wow, such duration")
👍 1
p

Pascal How

03/07/2018, 10:09 AM
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

gildor

03/07/2018, 10:27 AM
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