3.3: Using The Android Support Libraries

Contents:

The Android SDK includes several libraries collectively called the Android support library. These libraries provide a number of features that are not built into the Android framework, including:

  • Backward-compatible versions of framework components: the support library allows apps running on older versions of the Android platform to support features made available on newer versions.
  • Additional layout and user interface elements
  • Support for different device form factors, such as TV or wearables
  • Components to support material design elements
  • Various other features such as palette support, annotations, percentage-based layout dimensions, and preferences.

What you should already KNOW

From the previous practicals you should be familiar with:

  • How to create projects in Android Studio.
  • The major components of your Android Studio project (manifest, resources, Java files, gradle build files).

What you will LEARN

  • How to verify that the the Android support libraries are available in Android Studio.
  • How to indicate support library classes in your app.
  • How to tell the difference between the values for compileSdkVersion, targetSdkVersion, and minSdkVersion.
  • How to recognize deprecated or unavailable APIs in your code.
  • Where to find more information on the Android support libraries.

What you will DO

In this practical, you will:

  • Create a new app with one textview and one button.
  • Verify that the Android Support Library is available on your system.
  • Explore the build.gradle for your app.
  • Manage class or method calls that are unavailable for the version of Android your app supports.
  • Use a compatibility class from the support library to provide backward-compatibility for your app.

App overview

In this practical you'll create an app called HelloCompat with one textview that displays "Hello World" on the screen, and one button, that changes the color of the text. There are 20 possible colors, defined as resources in the color.xml file, and each button click randomly picks one of those colors. HelloCompat app

The methods to get a color value from the app's resources have changed with different versions for the Android framework. This example uses the ContextCompat class, part of the Android support library, which allows you to use a method that works for all versions.

Task 1. Set up your project to use support libraries

For this task you'll set up a new project for the HelloCompat app and implement the layout and basic behavior.

1.1 Verify that the Android Support Library is available

The Android support libraries are downloaded as part of the Android SDK, and available in the Android SDK manager. In Android Studio, you'll use the Android Support Repository—the local repository for the support libraries—to get access to the library from within your gradle build files. In this task you'll verify that the Android Support Repository is downloaded and available for your projects.

  1. In Android Studio, select Tools > Android > SDK Manager, or click the SDK Manager SDK Manager icon icon.

    The SDK Manager preference pane appears. SDK Manager icon

  2. Click the SDK Tools tab and expand Support Repository.
  3. Look for Android Support Repository in the list.
  4. If Installed appears in the Status column, you're all set. Click Cancel.
  5. If Not installed or Update Available appears, click the checkbox next to Android Support Repository. A download icon should appear next to the checkbox. Click OK.
  6. Click OK again, and then Finish when the support repository has been installed.

1.2 Set up the project and examine build.gradle

  1. Create a new project called HelloCompat, and choose the Empty Activity template.

    On the Target Android Devices page, note that API 15: Android 4.0.3 (IceCreamSandwich) is selected for the minimum SDK. As you've learned in previous lessons, this is the oldest version of the Android platform your app will support. Minimum SDK section in Android Studio

  2. In Android Studio, make sure the Project pane is open and the Android tab is selected.
  3. Expand Gradle Scripts, if necessary, and open the build.gradle (Module: app) file.

    Note that build.gradle for the overall project (build.gradle (Project: app_name)) is a different file from the build.gradle for the app module.

  4. Locate the compileSdkVersion line near the top of the file. For example:

    compileSdkVersion 24
    

    The compile version is the Android framework version your app is compiled with in Android Studio. For new projects the compile version is the most recent set of framework APIs you have installed. This value affects only Android Studio itself and the warnings or errors you get in Android Studio if you use older or newer APIs.

  5. Locate the minSdkVersion line in the defaultConfig section a few lines down.

    minSdkVersion 15
    

    The minimum version is the oldest Android API version your app runs under. It's the same number you chose in Step 1 when you created your project. The Google Play store uses this number to make sure your app can run on a given user's device. Android Studio also uses this number to warn you about using deprecated APIs.

  6. Locate the targetSdkVersion line in the defaultConfig section. For example:

    targetSdkVersion 24
    

    The target version indicates the API version your app is designed and tested for. If the API of the Android platform is higher than this number (that is, your app is running on a newer device), the platform may enable compatibility behaviors to make sure your app continues to work the way it was designed to. For example, Android 6.0 (API 23) provides a new runtime permissions model. If your app targets a lower API level, the platform falls back to the older install-time permissions model.

    Although the target SDK can be the same number as the compile SDK, it is often a lower number that indicates the most recent version of the API for which you have tested your app.

  7. Locate the dependencies section of build.gradle, near the end of the file. For example:

    dependencies {
        compile fileTree(dir: 'libs', include: ['*.jar'])
        androidTestCompile(
            'com.android.support.test.espresso:espresso-core:2.2.2', {
            exclude group: 'com.android.support',
                module: 'support-annotations'
        })
        compile 'com.android.support:appcompat-v7:24.2.1'
        testCompile 'junit:junit:4.12'
    }
    

    The dependencies section for a new project includes several dependencies to enable testing with Espresso, JUnit, as well as the v7 appcompat support library. Note that the version numbers for these libraries in your project may be different than those shown here.

    The v7 appcompat support library provides backward-compatibility for older versions of Android all the way back to API 9. It includes the v4 compat library as well, so you don't need to add both as a dependency.

  8. Update the version numbers, if necessary.

    If the current version number for a library is lower than the currently available library version number, Android Studio will highlight the line and warn you that a new version is available. ("a newer version of com.android.support:appcompat-v7 is available"). Edit the version number to the updated version.

    Tip: You can also click anywhere in the highlight line and type Alt-Enter (Option-Enter on the Mac). Select "Change to XX.X.X" from the menu, where XX.X.X is the most up-to-date version available.
  9. Update the compileSdkVersion number, if necessary.

    The major version number of the support library (the first number) must match your compileSdkVersion. When you update the support library version you may also need to update compileSdkVersion to match.

  10. Click Sync Now to sync your updated gradle files with the project, if prompted.
  11. Install missing SDK platform files, if necessary.

    If you update compileSdkVersion you may need to install the SDK platform components to match. Click Install missing platform(s) and sync project to start this process.

1.3 Add the layout and colors

In this task, modify the layout for the app.

  1. Open res/layout/activity_main.xml. In the Layout Editor, click the Text tab at the bottom of the screen and change the root view group to RelativeLayout, as you've done in previous exercises.
  2. If the TextView element includes any layout-contraint attributes, remove them.
  3. Modify the TextView element to have these attributes:

    Attribute Value
    android:id "@+id/hello_textview"
    android:layout_width "match_parent"
    android:layout_height "wrap_content"
    android:padding "@dimen/activity_horizontal_margin"
    android:gravity "center"
    android:textSize "100sp"
    android:textStyle "bold"
    android:text "Hello World!"
  4. Extract the string for "Hello World" into a string resource.
  5. Add a Button view under the TextView, and add these attributes:

    Attribute Value
    android:id "@+id/color_button"
    android:layout_width "match_parent"
    android:layout_height "wrap_content"
    android:layout_alignParentBottom "true"
    android:paddingTop "@dimen/activity_vertical_margin"
    android:text "Change Color"
    android:onClick "changeColor"
  6. Extract the string for "Change Color" into a string resource.
  7. Open res/values/colors.xml.
  8. Add these color resources to the file:
    <color name="red">#F44336</color>
    <color name="pink">#E91E63</color>
    <color name="purple">#9C27B0</color>
    <color name="deep_purple">#673AB7</color>
    <color name="indigo">#3F51B5</color>
    <color name="blue">#2196F3</color>
    <color name="light_blue">#03A9F4</color>
    <color name="cyan">#00BCD4</color>
    <color name="teal">#009688</color>
    <color name="green">#4CAF50</color>
    <color name="light_green">#8BC34A</color>
    <color name="lime">#CDDC39</color>
    <color name="yellow">#FFEB3B</color>
    <color name="amber">#FFC107</color>
    <color name="orange">#FF9800</color>
    <color name="deep_orange">#FF5722</color>
    <color name="brown">#795548</color>
    <color name="grey">#9E9E9E</color>
    <color name="blue_grey">#607D8B</color>
    <color name="black">#000000</color>
    

These color values and names come from the recommended color palettes for Android apps defined at Material Design - Style - Color. The codes indicate color RGB values in hexadecimal.

Solution code (activity_main.xml) Depending on your version of Android Studio, your code will look something like the following.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   android:id="@+id/activity_main"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:paddingBottom="@dimen/activity_vertical_margin"
   android:paddingLeft="@dimen/activity_horizontal_margin"
   android:paddingRight="@dimen/activity_horizontal_margin"
   android:paddingTop="@dimen/activity_vertical_margin"
   tools:context="com.example.android.hellocompat.MainActivity">

   <TextView
       android:id="@+id/hello_textview"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:gravity="center"
       android:padding="@dimen/activity_horizontal_margin"
       android:text="@string/hello_text_string"
       android:textSize="100sp"
       android:textStyle="bold" />

   <Button
       android:id="@+id/color_button"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_alignParentBottom="true"
       android:onClick="changeColor"
       android:paddingTop="@dimen/activity_vertical_margin"
       android:text="@string/button_label" />
</RelativeLayout>

1.4 Add behavior to MainActivity

In this task you'll finish setting up the project by adding private variables and implementing onCreate() and onSaveInstanceState().

  1. Open MainActivity.java.
  2. Add a private variable at the top of the class to hold the TextView object for the Hello World textview.
    private TextView mHelloTextView;
    
  3. Add the following color array just after the private variable:

    private String[] mColorArray = {"red", "pink", "purple", "deep_purple",
        "indigo", "blue", "light_blue", "cyan", "teal", "green",
        "light_green", "lime", "yellow", "amber", "orange", "deep_orange",
        "brown", "grey", "blue_grey", "black"
    };
    

    Each of these color names correspond to the names of the color resources from color.xml.

  4. In the onCreate() method, use findViewById() to get a reference to the TextView instance and assign it to that private variable:
    mHelloTextView = (TextView) findViewById(R.id.hello_textview);
    
  5. Also in onCreate(), restore the saved instance state, if any:
    // restore saved instance state (the text color)
    if (savedInstanceState != null) {
        mHelloTextView.setTextColor(savedInstanceState.getInt("color"));
    }
    
  6. Add the onSaveInstanceState() method to MainActivity to save the text color:

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
    
        // save the current text color
       outState.putInt("color", mHelloTextView.getCurrentTextColor());
    }
    

Solution code (not the whole class)

// Text view for Hello World.
private TextView mHelloTextView;
// array of color names, these match the color resources in color.xml
private String[] mColorArray = {"red", "pink", "purple", "deep_purple",
    "indigo", "blue", "light_blue", "cyan", "teal", "green",
    "light_green", "lime", "yellow", "amber", "orange", "deep_orange",
    "brown", "grey", "blue_grey", "black"
};
...
@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);

   // Initialize the main text view
   mHelloTextView = (TextView) findViewById(R.id.hello_textview);

   // restore saved instance state (the text color)
   if (savedInstanceState != null) {
       mHelloTextView.setTextColor(savedInstanceState.getInt("color"));
   }
}
...
@Override
public void onSaveInstanceState(Bundle outState) {
   super.onSaveInstanceState(outState);

   // save the current text color
   outState.putInt("color", mHelloTextView.getCurrentTextColor());
}

Task 2. Implement button behavior

The Change Color button in the HelloCompat app picks one of the 20 colors from the color.xml resource file at random and sets the color of the text to that color. In this task you'll implement the onClick() behavior for this handler.

2.1 Add the changeButton() onClick handler

  1. Open res/layout/activity_main.xml, if it is not already open.
  2. Click anywhere in the android:onClick attribute, inside the Button element.
  3. Press Alt-Enter (Option-Enter on the Mac), and select Create onClick event handler.
  4. Choose MainActivity and click OK.

    This creates a placeholder method stub for the changeColor() method in MainActivity.java.

2.2 Implement the button action

  1. Open MainActivity.java, if it is not already open.
  2. In the changeColor() method, create a random number object.

    Random random = new Random();
    

    Use the Random class (a Java class) to generate simple random numbers.

  3. Use the random instance to pick a random color from the mColorArray array:

    String colorName = mColorArray[random.nextInt(20)];
    

    The nextInt() method with the argument 20 gets another random integer between 0 and 19. Use that integer as the index of the array to get a color name.

  4. Get the resource identifier (an integer) for the color name out of the resources:

    int colorResourceName = getResources().getIdentifier(colorName,
        "color", getApplicationContext().getPackageName());
    

    When your app is compiled, the Android system converts the definitions in your XML files into resources with internal integer IDs. There are separate IDs for both the names and the values. This line matches the color strings from the colorName array with the corresponding color name IDs in the XML resource file. The getResources() method gets all the resources for your app. The getIdentifier() method looks up the color name (the string) in the color resources ("color") for the current package name.

  5. Get the integer ID for the actual color from the resources and assign it to a colorRes variable:

    int colorRes = getResources().getColor(colorResourceName);
    

    The getResources() method gets the set of resources for your app, and the getColor() method retrieves a specific color from those resources by the ID of the color name.

    Note that the getColor() method appears with a strikethrough in the Android Studio editor. If you hover your mouse over getColor(), the error "getColor(int) is deprecated" appears. In API 23, the getColor() method was modified to include a second argument for the app's theme. Since your app has a compileSdkVersion of 24 (or higher), Android Studio provides this warning that you're using an older, deprecated method.

    You can still compile your app and it would still run on both new and old Android devices -- the deprecation warning is a warning, not an error. But it's best not to ignore warnings where they exist, as deprecated methods can result in unexpected behavior.

  6. Change the colorRes assignment line to include the second argument to getColor():

    int colorRes =
        getResources().getColor(colorResourceName, this.getTheme());
    

    You can use the getTheme() method to get the theme for the current application context. Only now with this change you'll note that getColor() has a red underlined highlight. If you hover over getColor() Android Studio reports: "Call requires API 23 (current min is 15)". Since your minSdkVersion is 15, you'll get this message if you try to use any APIs that were introduced after API 15. You can still compile your app, but because this new version of getColor() with two arguments is not available on devices prior to API 23, your app will crash when the user taps the Change button.

    At this stage you could check for the platform version and use the right version of getColor() depending on where the app is running. (you will still get a warning for both calls in Android Studio). The better way to support both older and newer Android APIs without warnings is to use one of the compatibility classes in the support library.

  7. Change the colorRes assignment line to use the ContextCompat class:

    int colorRes = ContextCompat.getColor(this, colorResourceName);
    

    ContextCompat provides many compatibility methods to address API differences in the application context and app resources. The getColor() method in ContextCompat takes two arguments: the current context (here, the activity instance, this), and the name of the color.

    The implementation of this method in the support library hides the implementation differences in different versions of the API. You can call this method regardless of your compile SDK or minimum SDK versions with no warnings, errors, or crashes.

  8. Set the color of the Hello World text view to the color resource ID:
    mHelloTextView.setTextColor(colorRes);
    
  9. Compile and run the app on a device or emulator.

    The Change Color button should now change the color of the text in Hello World.

Solution code (changeColor() method only)

public void changeColor(View view) {
   // get a random color name from the color array (20 colors)
   Random random = new Random();
   String colorName = mColorArray[random.nextInt(20)];

   // get the color identifier that matches the color name
   int colorResourceName = getResources().getIdentifier(colorName, "color",
       getApplicationContext().getPackageName());

   // get the color ID from the resources
   int colorRes = ContextCompat.getColor(this, colorResourceName);

   // Set the text color
   mHelloTextView.setTextColor(colorRes);
}

Solution code

Android Studio project: HelloCompat

Coding challenge

Note: All coding challenges are optional and are not prerequisites for later lessons.

Challenge: Instead of using ContextCompat for to get the color resource, use a test of the values in the Build class to perform a different operation if the app is running on a device that supports less than API 23.

Summary

In this practical, you learned that:

  • Android uses three directives to indicate how your app should behave for different API versions:
    • minSdkVersion: the minimum API version your app supports.
    • compileSdkVersion: the API version your app should be compiled with.
    • targetSdkVersion: the API version your app was designed for.
  • The Android Support Library can be installed in the SDK manager
  • You can add library dependencies for support libraries in the gradle.build file
  • The ContextCompat class provides methods for compatibility with context and resource-related methods for both old and new API levels.

The related concept documentation is in Android Developer Fundamentals: Concepts.

Learn more

results matching ""

    No results matching ""