A relatively common task is to have some kind of animation between Activities in Android. The default animation isn’t necessarily always the same across devices, and sometimes it is desirable to customize this. A quick look at the docs will lead you to the overridePendingAnimation method of Activity. Perfect! You just activate this method immediately after calling finish()
or startActivity()
and it works exactly how you would expect… well, unless the device isn’t running at least Android 2.0. It’s very easy to miss the “Since API Level 5″ note in the documentation (you should definitely take advantage of the “filter by API level” feature in the top right of the Android developer site) and adding this method to your code and trying to run it on a previous version of Android will result in a force-closed Activity.
Chances are you don’t want to limit your Android app to 2.0 and above just to have a nice transitional animation between Activities. You could modify all of your code to use animations tied to Views, but that’s not what you really want to do. Instead, you should rely on Java’s reflection (i.e., the ability for your code to analyze itself at runtime). What you want to do is check to see if the overridePendingTransition
method exists and use it only if it does. Otherwise, your code should just let the normal action take place. Here’s a simplified example:
static public void setActivityAnimation(Activity activity, int in, int out) { try { Method method = Activity.class.getMethod("overridePendingTransition", new Class[]{int.class, int.class}); method.invoke(activity, in, out); } catch (Exception e) { // Can't change animation, so do nothing } }
This is a static method I typically have in a LayoutUtils class that I create for convenience (see below for a better implementation). You pass it a reference to your Activity (this
within your Activity) and the int resource IDs to the in animation and out animation.
Line 3 is attempting to create a Method object that essentially represents the method we want to call. You pass the name of the method as well as the argument types that the method takes (two ints). This line will throw a NoSuchMethodException on Android 1.5 and 1.6, but you also have to catch a SecurityException (which won’t ever be thrown in this case), and the next line which actually invokes the method can throw an IllegalArgumentException, IllegalAccessException, or InvocationTargetException. To keep this example simple, I set the code to catch all Exceptions and then do nothing. In general, it’s a bad idea to catch an Exception and then do nothing, but “doing nothing” really just means we’re letting the default animation (if any) happen. While testing this out, you may want to add a Log.d() call in the catch block to see exactly what is happening.
That’s all there is to it. With reflection, we’re able to let devices running Android 2.0 and above animate during Activity transitions, while still making the app accessible to earlier versions of Android. Of course, it’s best to avoid using reflection a lot because it is not particularly efficient. A common way to avoid that is to set a reference to the Method you wish to invoke once like this:
/** * Method for invoking overridePendingTransition */ private static final Method sOverridePendingTransitionMethod = setOverridePendingTransitionMethod(); /** * Returns a Method for overridePendingTransition or null * * @return */ static private Method setOverridePendingTransitionMethod() { try { return Activity.class.getMethod("overridePendingTransition", new Class[]{int.class, int.class}); } catch (SecurityException e) { // Method not available } catch (NoSuchMethodException e) { // Method not available } // No method available, so return null return null; }
Now, instead of using reflection in the setActivityAnimation method, you check for null and invoke the Method if it’s not null:
/** * Safe method for invoking Activity animations via overridePendingTransition * * @param activity * @param in * @param out */ static public void setActivityAnimation(Activity activity, int in, int out) { if (sOverridePendingTransitionMethod != null) { try { sOverridePendingTransitionMethod.invoke(activity, in, out); } catch (IllegalArgumentException e) { // Don't customize animation } catch (IllegalAccessException e) { // Don't customize animation } catch (InvocationTargetException e) { // Don't customize animation } } }
Now you’re only checking for null when you invoke this method instead of using reflection with every call. Although the performance benefit isn’t particularly significant in this example (you’re probably not calling setActivityAnimation
very frequently), storing the results of an expensive call that will always return the same value is a good habit to get into.