In one of our methods, we use smoothScrolling in a list view. As this method is not available before API Level 8 (FROYO), we used the TargetApi annotation to prevent the method from being called in previous SDK versions.
As you can see, we do use TargetApi annotation both in class definition and in statements that use the objects of the class. This is more than needed.
Our problem is that the TargetApi annotation is not taken into account and make our emulator crash in version ECLAIR (SDK 7). By tracing, we just realize that the code that should only be executed in versions 8+ is also executed in version 7.
Are we missing something?
This code is in a listener :
@TargetApi(8)
private final class MyOnMenuExpandListener implements OnMenuExpandListener {
@Override
public void onMenuExpanded( int position ) {
doScrollIfNeeded( position );
}
@Override
public void onMenuCollapsed( int position ) {
doScrollIfNeeded( position );
}
protected void doScrollIfNeeded( int position ) {
if ( mListViewDocuments.getLastVisiblePosition() - 2 < position ) {
mListViewDocuments.smoothScrollToPosition( position + 1 );
}
}
}
And the listener is registered this way :
@TargetApi(8)
private void allowSmothScrollIfSupported() {
if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO ) {
//This if should not be necessary with annotation but it is not taken into account by emulator
Log.d( LOG_TAG, "Smooth scroll support installed." );
folderContentAdapter.setOnMenuExpandListener( new MyOnMenuExpandListener() );
}
}
BTW, we run the code in debug mode, so the issue is not related to obfuscation removing annotations.
To enforce lint error when using a method targeted towards higher Api Level, you can use
RequiresApi
instead ofTargetApi
and whenever you'll try to use the method without checking the version code, you'll get compilation error.This is what the documentation says about RequiresApi
With almost one year of more thinking about this, I would like to add a tiny complement to @Guykun 's answer :
The @TargetApi will be only be used by tools to say developers "Hey, don't use this method below XXX android SDK". Typically lint.
So, if you design a method like :
then you should add @TargetApi( 7 ) to your method's signature.
BUT, if you add an else statement, and provide an alternative that makes it work for all versions of Android like :
then you should not add @TargetApi( 7 ) to your method's signature. Otherwise, other developers will think they can't use your method belw api level 7, but indeed, it would work for them as well.
So this annotation has to be used, for static analysis, to indicate the minimum api level supported by the method. As in :
and even better, use constants defined in
android.Build.VERSION_CODES.*
.BTW, you would have noticed that this is useless for private methods indeed, except to get a cleaner code and help to promote the method public in the future.
@TargetApi
does not prevent any code from being run, it is merely for annotating code and preventing compiler errors for new APIs once you know you are only conditionally calling them.You still need to add something along the lines of