You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Following #148 and #245, there is a problem with declaring listener annotations having the same names for different targets.
There are different types of targets having listeners with the same names, yet those don't expect the same amount/types/order of arguments, or even if they do, it is possible that there are/will be definitions for multiple identical listener interfaces for different types of targets. So eventually you end up with something like RadioGroup.OnCheckedChangeListener and CompoundButton.OnCheckedChangeListener. I was able to come up with the following solutions given how Butter Knife works:
A: Define listener annotations in packages corresponding to the target type. Examples:
butterknife.compoundbutton.OnCheckedChanged
butterknife.radiogroup.OnCheckedChanged
Probably the biggest downside of this approach is that if you wish to use two (or more) annotations having the same name in the same file, you will end up specifying the fully qualified name of at least one of them every time you use it.
B: Prefix the annotation name with the corresponding target type. Examples:
butterknife.CompoundButtonOnCheckedChange
butterknife.RadioGroupOnCheckedChange
butterknife.AdapterViewOnItemLongClick
butterknife.ViewOnClick
butterknife.ViewOnFocusChanged
Both A and B are about declaring multiple annotations, following the rule of one annotation per target. The only benefit with these approaches as I see it is the fact that this doesn't require any changes to the underlying processor.
Obviously both approaches require modifying all existing listener annotations to follow one of these formats in order to keep the API consistent.
C: Support multiple target types per annotation.
Consider the current code for OnCheckedChanged.java:
@ListenerClass(
targetType = "android.widget.CompoundButton",
setter = "setOnCheckedChangeListener",
type = "android.widget.CompoundButton.OnCheckedChangeListener",
method = @ListenerMethod(
name = "onCheckedChanged",
parameters = {
"android.widget.CompoundButton",
"boolean"
}
)
)
public @interface OnCheckedChanged {
/** View IDs to which the method will be bound. */int[] value() default { View.NO_ID };
}
If we add support to the processor for multiple targets, we could use something like the following:
@ListenerClassList({
@ListenerClass(
targetIdentifier = "CompoundButton",
targetType = "android.widget.CompoundButton",
setter = "setOnCheckedChangeListener",
type = "android.widget.CompoundButton.OnCheckedChangeListener",
method = @ListenerMethod(
name = "onCheckedChanged",
parameters = {
"android.widget.CompoundButton",
"boolean"
}
)
),
@ListenerClass(
targetIdentifier = "RadioGroup",
targetType = "android.widget.RadioGroup",
setter = "setOnCheckedChangeListener",
type = "android.widget.RadioGroup.OnCheckedChangeListener",
method = @ListenerMethod(
name = "onCheckedChanged",
parameters = {
"android.widget.RadioGroup",
"int"
}
)
)
})
public @interface OnCheckedChanged {
/** View IDs to which the method will be bound. */int[] value() default { View.NO_ID };
Stringtarget();
}
This way, users of the library have to explicitly specify the type of listener they're interested in by providing a listener target identifier, for example:
Sure, this means slightly more code (which kind of works against boilerplate reduction), but I think this is a much more generic solution that could also be beneficial in the future for other use cases.
Note that the listener identifier should probably be an enum or a different type of constant provided by the library.
One final note is that for listeners with only one available target type it will be used by default.
If C sounds like a 👍 I would be happy to submit a PR introducing this functionality.
Thoughts?
The text was updated successfully, but these errors were encountered:
tomxor
changed the title
Support listeners with the same name
Support listeners with identical names
Mar 21, 2015
Following #148 and #245, there is a problem with declaring listener annotations having the same names for different targets.
There are different types of targets having listeners with the same names, yet those don't expect the same amount/types/order of arguments, or even if they do, it is possible that there are/will be definitions for multiple identical listener interfaces for different types of targets. So eventually you end up with something like
RadioGroup.OnCheckedChangeListener
andCompoundButton.OnCheckedChangeListener
. I was able to come up with the following solutions given how Butter Knife works:A: Define listener annotations in packages corresponding to the target type. Examples:
Probably the biggest downside of this approach is that if you wish to use two (or more) annotations having the same name in the same file, you will end up specifying the fully qualified name of at least one of them every time you use it.
B: Prefix the annotation name with the corresponding target type. Examples:
Both A and B are about declaring multiple annotations, following the rule of one annotation per target. The only benefit with these approaches as I see it is the fact that this doesn't require any changes to the underlying processor.
Obviously both approaches require modifying all existing listener annotations to follow one of these formats in order to keep the API consistent.
C: Support multiple target types per annotation.
Consider the current code for
OnCheckedChanged.java
:If we add support to the processor for multiple targets, we could use something like the following:
This way, users of the library have to explicitly specify the type of listener they're interested in by providing a listener target identifier, for example:
Sure, this means slightly more code (which kind of works against boilerplate reduction), but I think this is a much more generic solution that could also be beneficial in the future for other use cases.
Note that the listener identifier should probably be an enum or a different type of constant provided by the library.
One final note is that for listeners with only one available target type it will be used by default.
If C sounds like a 👍 I would be happy to submit a PR introducing this functionality.
Thoughts?
The text was updated successfully, but these errors were encountered: