I have been creating Spinner controls (Combo boxes/Drop downs) in one of my apps, and was surprised to find out how difficult it was to achieve all of the following features:
- User facing Strings are externalized, taking advantage of strings.xml internationalisation (I18N) feature of Android.
- Spinner selections operate using a System view, which facilitates not having to work with or map Strings to meaningful values (yuck).
- User view to System view mapping should be easy, automated and minimal (i.e not hand rolled for every component).
Others have attempted solutions to this, but universally as far as I could see they suffer from one or many of the following problems:
- UI code is creeping into their enum class which doesn’t belong there (messy), nearly all existing solutions suffered from this.
- Hardcoded User facing Strings in their enum classes. Because these are not externalized you cannot do I18N using the stock Android features.
- Authors typically make the Fragment or Activity an OnItemSelectedListener which perpetuates a common problem of inheritance for convenience, where composition is more appropriate.
I have developed my own solution which does this: http://www.androidanalyse.com/android-spinner-externalize-user-strings-mapped-to-system-enum/
My question is, have I missed something? This seems like something that should not have been this hard (which makes me feel like I’m possibly reinventing the wheel).
Below is some example code showing my solution in-use (which is available Apache 2 license from the link above).
String none = getString(R.string.none);
String light = getString(R.string.light);
String medium = getString(R.string.medium);
String strong = getString(R.string.strong);
SpinnerUtil.createNewSpinner(view, R.id.wind, Arrays.asList(none, light, medium, strong), WindLevel.values(),
new SpinnerItemSelectedListener<WindLevel>() {
public void onItemSelected(Spinner item, WindLevel value) {
// Take whatever action you wish to here.
}});
I would just use
ArrayAdapter<WindLevel>. Yes, you created a custom typed listener, but the regular event listener gets thepositionand can callgetItem()on theArrayAdapter<WindLevel>to get aWindLevelproperly typed.IMHO, the vast majority of
Spinnerwidgets will be populated with material read in from a database, the Internet, or some other dynamic data source, rather than populated by some sort of enum with display values coming from static strings that can be internationalized ahead of time.This is not to say that your code is useless: if you find it useful, then it was worth writing. And I am sure that there are apps out there that contain your targeted pattern (i.e., a
Spinnerbacked by an enum or equivalent where the display values are known in advance and can be internationalized) who might find your solution useful as well. Every developer who writes enough code cooks up these sorts of helper classes and the like that help map an OS or framework model into something that better fits the developer’s own mental model. So long as you are not perceiving any performance issues, it’s all good.Also, note that
OnItemSelectedListeneris an interface; implementing that interface on an existing class is not inheritance.