Spinner: plug an Adapter into an AdapterView

Tap the yellow Spinner and select a metal. I made it yellow so you could see how big the spinner is. Earlier versions of Android gave the spinner an underline, so you could see how wide it was without needing a color.

An Adapter takes a series of data items (strings, numbers, images) and encases each one in a separate View. The simplest example of an Adapter is an ArrayAdapter, which gets its data from a Java array. Our array is an array of Strings, and our ArrayAdapter is therefore an ArrayAdapter<String>. It encases each String in a TextView.

The Adapter does not actually display the views on the screen; it only creates them and puts a data item into each one. The views are displayed by another object called an AdapterView, which is a big view that displays smaller views inside it. (In other words, an AdapterView is a ViewGroup.) The simplest example of an AdapterView is a Spinner (dropdown menu). See Spinners. The AdapterView calls the getCount and getView methods of the Adapter.

The first parameter of onItemSelected is the AdapterView (in this case, the Spinner) and the second parameter is the View that was selected (in this case, a TextView) in the AdapterView. The third parameter (int position) is the zero-based position of the selected item in the AdapterView. This parameter is an int because an AdapterView will never display more than a few items on the screen. The fourth parameter (long id) is the position of the selected item in the Adapter’s source of data. In this case, the Adapter’s source of data is the Java array of Strings, so the id is the subscript of the string in the array. This parameter is a long because the Adapter’s source of data might be a database with many billions of records. Our Adapter always sends its data items to the AdapterView in the order in which they are stored in its source of data (the Java array), so our position and id will always be the same number. For an Adapter that sends its data items AdapterView in a different order, see CursorAdapter.

Unfortunately, the firstTime kludge was necessary to prevent onItemSelected from being called when the app was launched.

Source code in Spinner.zip

  1. MainActivity.java
  2. spinner/R.java creates the variables R.layout.activity_main and R.id.spinner.
  3. activity_main.xml: the white RelativeLayout contains a yellow Spinner.
  4. strings.xml: unchanged.
  5. styles.xml. This file is in the res/values directory and defines the theme AppTheme mentioned in AndroidManifest.xml.
  6. AndroidManifest.xml: the android:theme attribute of the application element specifies the activity’s theme.
  7. build.gradle (Module: app).

Documentation

  1. A spinner is called a simple menu in the Material Design spec.
  2. Spinners in the User Interface guide.
  3. The Java class android.widget.Spinner
    1. Documentation
    2. Source code on GitHub: platform_frameworks_base/core/java/android/widget/Spinner.java
  4. The Java class android.widget.AdapterView.OnItemSelectedListener
    1. Documentation
    2. Source code on GitHub: platform_frameworks_base/core/java/android/widget/AdapterView.java lines 359–388
  5. XML source code on GitHub
    1. android/platform/frameworks/base/master/./core/res/res/layout/simple_spinner_item.xml
    2. android/platform/frameworks/base/master/./core/res/res/layout/simple_spinner_dropdown_item.xml

simple_spinner_item.xml

An unexpanded Spinner is displayed as the TextView in the following file
~/Library/Android/sdk/platforms/android-24/data/res/layout/simple_spinner_item.xml
(shown without its <?xml> tag and copyright notice). The identifying number of this file is
android.R.layout.simple_spinner_item
This id number starts with android.R because the file is on your hard disk. A file that is part of your app (e.g., activity_main.xml) has an id number that starts with R (e.g., R.layout.activity_main).

A question mark refers to an attribute of the current theme. See Referencing style attributes.

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/text1"
    style="?android:attr/spinnerItemStyle"
    android:singleLine="true"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:ellipsize="marquee"
    android:textAlignment="inherit"/>

simple_spinner_dropdown_item.xml

Each line of an expanded Spinner is displayed as the CheckedTextView in the following the file
~/Library/Android/sdk/platforms/android-24/data/res/layout/simple_spinner_dropdown_item.xml
The identifying number of this file is
android.R.layout.simple_spinner_dropdown_item

The check is visible only when the AdapterView is a ListView.

<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/text1"
    style="?android:attr/spinnerDropDownItemStyle"
    android:singleLine="true"
    android:layout_width="match_parent"
    android:layout_height="?android:attr/dropdownListPreferredItemHeight"
    android:ellipsize="marquee"/>

Spinner in ApiDemos

  1. Views → Spinner
    1. platform_development/samples/ApiDemos/src/com/example/android/apis/view/Spinner1.java
    2. platform_development/samples/ApiDemos/res/layout/spinner_1.xml
    3. platform_development/samples/ApiDemos/res/values/strings.xml lines 1275–1278
    4. platform_development/samples/ApiDemos/res/values/arrays.xml lines 18–39
    5. android/platform/frameworks/base/master/./core/res/res/layout/simple_spinner_item.xml
    6. android/platform/frameworks/base/master/./core/res/res/layout/simple_spinner_dropdown_item.xml

Things to try

  1. Is onItemSelected called when the user selects a selection that is already selected?

  2. In the above screenshots, the Spinner opened below its closed location. In activity_main.xml, change android:layout_centerInParent="true" to android:layout_alignParentBottom="true". Observe that the Spinner now opens above its closed location.

  3. Can the array of strings change while the program is running? A simple change would be to sort the array in alphabetical order by inserting the following statement before the call to setAdapter. The String.CASE_INSENSITIVE_ORDER is an object of class Comparator<String>.
            arrayAdapter.sort(String.CASE_INSENSITIVE_ORDER);
    

  4. Can you create the Adapter without giving a name to the Java array?
            ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(
                    this,
                    android.R.layout.simple_spinner_item,
                    new String[] {"copper", "iron", "steel", "Rearden Metal"}
            );
    

  5. Create the ArrayAdapter with a string array resource in a .xml file in the app/res/values directory. Follow these directions.
    1. Edit the file app/res/values/strings.xml.
      <?xml version="1.0" encoding="utf-8"?>
      <resources>
      
          <string name="app_name">Spinner</string>
      
          <string-array name="metals_array">
              <item>copper</item>
              <item>iron</item>
              <item>steel</item>
              <item>Rearden Metal</item>
          </string-array>
      
      </resources>
      
    2. Create the ArrayAdapter from the above string array resource. CharSequence is a Java interface implemented by class String.
      			ArrayAdapter<CharSequence> arrayAdapter = ArrayAdapter.createFromResource(
      				this,
      				R.array.metals_array,
      				android.R.layout.simple_spinner_item
                              );
      
      			arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
      

  6. Let activity_main.xml create the ArrayAdapter. Remove the ArrayAdapter from onCreate. Keep the metals_array string array resource we just added to strings.xml. Add the following attribute to the Spinner element in activity_main.xml.
            android:entries="@array/metals_array"
    

  7. Even though the file simple_spinner_dropdown_item.xml contains a CheckedTextView, the second parameter actually passed to onItemSelected is a TextView. Why?

  8. Why is each line of the expanded spinner higher than the one line of the unexpanded spinner? The dropdownListPreferredItemHeight in simple_spinner_dropdown_item.xml is defined in
    ~/Library/Android/sdk/platforms/android-24/data/res/values/themes_holo.xml
    to be equal to listPreferredItemHeightSmall, which is defined in the same file to be 48 dp = 48/160 inches = .3 inches.