Tutorial Details
- Program: Java with Android Focus
- Difficulty: Beginner
- Estimated Completion Time: 45-60 Minutes
- Learn Java for Android Development: Introduction to Java
- Learn Java for Android Development: Java Syntax
- Learn Java for Android Development: Checking Object Type with Instanceof
- Learn Java for Android Development: Working with Arrays
- Learn Java for Android Development: Reflection Basics
- Learn Java for Android Challenge: Iteration
- Learn Java for Android Development: Inner Classes
- Learn Java for Android Development: More On Inner Classes
- Learn Java for Android Development: Javadoc Code Documentation
- Learn Java for Android Development: String Basics
- Learn Java for Android Development: Date and Time Basics
- Learn Java for Android Challenge: Strings
- Learn Java for Android Development: Java Shorthand
Android applications are written in the Java, a programming language that supports reflection—the ability of an object to examine itself. In this tutorial, you’ll learn the basics of Java reflection, including how to inspect the methods and fields of a given class, check for the availability of specific methods, and other practical tasks you may need to use when developing for different versions of the Android SDK.
What You’ll Need
Technically, you don’t need any tools to complete this tutorial but you will certainly need them to develop Android applications.To develop Android applications (or any Java applications, for that matter), you need a development environment to write and build applications. Eclipse is a very popular development environment (IDE) for Java and the preferred IDE for Android development. It’s freely available for Windows, Mac, and Linux operating systems.
For complete instructions on how to install Eclipse (including which versions are supported) and the Android SDK, see the Android developer website.
Why Use Reflection?
Reflection gives developers the flexibility to inspect and determine API characteristics at runtime, instead of compile time. Within the security constraints imposed by Java (e.g. use of public, protected, private), you can then construct objects, access fields, and invoke methods dynamically. The Java Reflection APIs are available as part of the java.lang.reflect package, which is included within the Android SDK for developers to use.So what does this have to do with Android development? Well, with each new version of the Android SDK, classes, interfaces, methods, etc. are added, updated, and (less frequently) removed. However, Android developers often want to target devices running different versions of Android with a simple application package. To do this, Android developers may use reflection techniques to determine, at runtime, if a specific class or method is available before trying to use it. This allows the developer to leverage new APIs where available while still supporting the older devices—all in the same application.
Inspecting Classes
Java classes are represented at runtime using the Class (java.lang.Class) class. This class provides the starting point for all reflection APIs. Within this class, you’ll find many methods for inspecting different aspects of a class, such as its fields, constructors, methods, permissions, and more. You can also use the Class method called forName() to load a non-primitive class (e.g. not int, but Integer) by name dynamically at runtime, instead of at compile time:- String sClassName = "android.app.NotificationManager";
- try {
- Class classToInvestigate = Class.forName(sClassName);
- // Dynamically do stuff with this class
- // List constructors, fields, methods, etc.
- } catch (ClassNotFoundException e) {
- // Class not found!
- } catch (Exception e) {
- // Unknown exception
- }
Inspecting the Constructors Available Within a Class
You can inspect the constructors available within a given Class. To get just the constructors that are publicly available, use getConstructors(). However, if you want to inspect those methods specifically declared within the class, whether they are public or not, use getDeclaredConstructors() instead. Both methods return an array of Constructor (java.lang.reflect.Constructor) objects.For example, the following code iterates through the declared constructors of a class:
- Constructor[] aClassConstructors = classToInvestigate.getDeclaredConstructors();
- for(Constructor c : aClassConstructors){
- // Found a constructor c
- }
Inspecting the Fields Available Within a Class
You can inspect the fields (or attributes) available within a given Class. To get just the methods that are publicly available, including inherited fields, use getFields(). However, if you want to inspect those fields specifically declared within the class (and not inherited ones), whether they are public or not, use getDeclaredFields() instead. Both methods return an array of Field (java.lang.reflect.Field) objects.For example, the following code iterates through the declared fields of a class:
- Field[] aClassFields = classToInvestigate.getDeclaredFields();
- for(Field f : aClassFields){
- // Found a field f
- }
- String sClassName = "android.content.Intent";
- try {
- Class classToInvestigate = Class.forName(sClassName);
- String strNewFieldName = "EXTRA_CHANGED_PACKAGE_LIST";
- Field newIn22 = classToInvestigate.getField(strNewFieldName);
- } catch (ClassNotFoundException e) {
- // Class not found
- } catch (NoSuchFieldException e) {
- // Field does not exist, likely we are on Android 2.1 or older
- // provide alternative functionality to support older devices
- } catch (SecurityException e) {
- // Access denied!
- } catch (Exception e) {
- // Unknown exception
- }
Inspecting the Methods Available Within a Class
You can inspect the methods available within a given Class. To get just the methods that are publicly available, including inherited methods, use getMethods(). However, if you want to inspect those methods specifically declared within the class (without inherited ones), whether they are public or not, use getDeclaredMethods() instead. Both methods return an array of Method (java.lang.reflect.Method) objects.
For example, the following code iterates through the declared methods of a class:
- Method[] aClassMethods = classToInvestigate.getDeclaredMethods();
- for(Method m : aClassMethods)
- {
- // Found a method m
- }
Inspecting Inner Classes
You can inspect the inner classes defined within a Class using getDeclaredClasses() method. This method will return an array of Class (java.lang.class) objects declared within the parent class. These classes can then be inspected like any other.Inspecting Member Modifiers
You can also inspect the flags and security settings—called modifiers—associated with a given Class, Field, or Method using the getModifiers() method. Interesting modifiers include whether the component is public, private, protected, abstract, final, or static (amongst others).For example, the following code checks the security modifiers of a class:
- int permissions = classToInvestigate.getModifiers();
- if(Modifier.isPublic(permissions)) {
- // Class is Public
- }
- if(Modifier.isProtected(permissions)) {
- // Class is Protected
- }
- if(Modifier.isPrivate(permissions)) {
- // Class is Private
- }
Inspecting Class Metadata
You can also inspect the metadata—called annotations—associated with a given class, field or method using the getAnnotations() method. Interesting metadata associated with a class might include information about deprecation, warnings, and overrides, among other things.For example, the following code checks the metadata available for the AbsoluteLayout class. Since this class was deprecated in Android 1.5, one of the annotations returned is @java.lang.Deprecated() when this code is run on Android 2.2:
- String sClassName = "android.widget.AbsoluteLayout";
- try {
- Class classToInvestigate = Class.forName(sClassName);
- Annotation[] aAnnotations = classToInvestigate.getDeclaredAnnotations();
- for(Annotation a : aAnnotations)
- {
- // Found an annotation, use a.toString() to print it out
- }
- } catch (ClassNotFoundException e) {
- // Class not found!
- } catch (Exception e) {
- // Handle unknown exception!
- }
- if(classToInvestigate.isAnnotationPresent(java.lang.Deprecated.class) == true)
- {
- // Class is deprecated!
- }
Reflection: Handy for Debugging
You can also use reflection to assist with debugging. For example, you might want to use the class keyword to access the underlying class data for a given type:- import android.app.Activity;
- …
- String strClassName = Activity.class.getName(); // android.app.Activity
- String silly = "Silly String!";
- Class someKindOfClass = silly.getClass();
- String strSillyClassName = someKindOfClass.getName(); // java.lang.String
Similarly, you might want to use the getClass() method with the this keyword to check the name of the class you’re currently in and include this information as part of your debug logging to LogCat:
- String strCurrentClass = this.getClass().getName(); // e.g. the current Activity
- Log.v(strCurrentClass, "Debug tag is current class.");