Recent Changes‎ > ‎

Lint API Check

posted Feb 15, 2012, 2:54 PM by Tor Norbye   [ updated Aug 30, 2013, 7:46 AM ]
Lint has been improved a lot for ADT 17. In addition to nearly doubling the number of available checks, the infrastructure has been improved a lot as well. It analyzes both Java source parse trees as well as the compiled byte code, which means it can detect a whole new class of issues.

Here's an example. Let's say you've decided that your Android app should support API 4 (Android 1.6 -- see Android API Levels) and up, so your manifest specifies

   <uses-sdk android:minSdkVersion="4" />

If you run lint, you may get errors like these:
src/com/example/android/apis/app/Animation.java:70: Error: Call requires API level 5 (current min is 4): android.app.Activity#overridePendingTransition [NewApi]
    overridePendingTransition(R.anim.zoom_enter, R.anim.zoom_exit);
    ^

src/com/example/android/apis/animation/AnimationCloning.java:80: Error: Call requires API level 11 (current min is 4): android.animation.ObjectAnimator#ofFloat [NewApi]
    ObjectAnimator anim1 = ObjectAnimator.ofFloat(balls.get(0), "y",
                                          ^

res/layout/switches.xml:35: Error: View requires API level 14 (current min is 4): <Switch> [NewApi]
    <Switch android:id="@+id/monitored_switch"
    ^

As you can see, lint now has a database of the full Android API such that it knows precisely which version each API call was introduced in. If it detects that you are attempting to call a method which is not available in all versions you are trying to support, it will warn you with messages like the above.

Of course, if you're building your project with the same version of Android as your oldest support version, the compiler will complain if it finds an API call it can't resolve. However, that approach has some downsides. In particular, you may want to access newer APIs on platforms where they are available. If you're compiling against the oldest version of the platform, you would need to use reflection to access all the new APIs, which can be really cumbersome, especially if you have a lot of code using the newer APIs.

The way most developers get around this is to actually use a newer build target, which means you can access all the new APIs directly. You then add some code checks to make sure that the code path which calls the newer APIs is only reached when running on a version which supports it. 

However, when you do this you run the risk of accidentally calling newer APIs, and that's what Lint now helps you detect.

What about code where you are deliberately calling newer APIs from a class you know will only be loaded in the right circumstances? In that case you can "mark" the code as targeting a newer version of the API. Simply annotate the code with the new @TargetApi annotation:
        @TargetApi(11)
        private void createAnimation() {
            if (animation == null) {
                // @TargetApi(11) - NOTE: you can't use the @TargetApi annotation inside methods, see issue 27511
                ObjectAnimator anim1 = ObjectAnimator.ofFloat(balls.get(0), "y",
                        0f, getHeight() - balls.get(0).getHeight()).setDuration(500);
                ObjectAnimator anim2 = anim1.clone();
                anim2.setTarget(balls.get(1));
                anim1.addUpdateListener(this);

If the whole class is targeting newer APIs, you can place the annotation on the class instead:
import java.util.ArrayList;

@TargetApi(11)
public class AnimationCloning extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {

We hope this check will help catch undiscovered bugs!
Comments