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.
When you upload an APK, it must meet Google Play's target API level requirements. New apps must target Android 12 (API level 31) or higher; except for Wear OS apps, which must target Android 11 (API level 30) or higher.
@RequiresApi - Denotes that the annotated element should only be called on the given API level or higher. @TargetApi - Indicates that Lint should treat this type as targeting a given API level, no matter what the project target is.
The Target Android Version (also known as targetSdkVersion ) is the API level of the Android device where the app expects to run. Android uses this setting to determine whether to enable any compatibility behaviors – this ensures that your app continues to work the way you expect.
@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
if (Build.VERSION.SDK_INT > 7){ //... }
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 :
if (Build.VERSION.SDK_INT > 7){ //... }
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 :
if (Build.VERSION.SDK_INT > 7){ //... } else { //... }
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 :
@TargetApi( 7 ) public void foo() { if (Build.VERSION.SDK_INT > 7){ //... else if (Build.VERSION.SDK_INT > 10){ //... } }
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With