【问题标题】:TargetApi not taken into account未考虑 TargetApi
【发布时间】:2012-08-31 07:52:41
【问题描述】:

在我们的一种方法中,我们在列表视图中使用了 smoothScrolling。由于该方法在 API Level 8 (FROYO) 之前不可用,因此我们使用 TargetApi 注解来防止在之前的 SDK 版本中调用该方法。

如您所见,我们确实在类定义和使用类对象的语句中都使用 TargetApi 注释。这比需要的多。

我们的问题是TargetApi注解没有被考虑在内,导致我们的模拟器在ECLAIR(SDK 7)版本中崩溃。通过追踪,我们才意识到,应该只在版本 8+ 中执行的代码,在版本 7 中也执行了。

我们错过了什么吗?

这段代码在监听器中:

@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 );
        }
    }
}

监听器是这样注册的:

@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() );
    }
}

顺便说一句,我们在调试模式下运行代码,所以问题与混淆删除注释无关。

【问题讨论】:

  • 顺便说一句,你可以写@TargetApi(Build.VERSION_CODES.FROYO)而不是@TargetApi(8)
  • 你是对的。为此,您的 targetSDK 必须尽可能高。

标签: android annotations emulation


【解决方案1】:

@TargetApi 不会阻止任何代码运行,它只是用于注释代码并防止新 API 的编译器错误,一旦您知道您只是有条件地调用它们。

你仍然需要添加一些类似的东西

if (Build.VERSION.SDK_INT > 7){
    //...
}

【讨论】:

  • 它所做的只是删除 lint 错误。检查here
  • 真的吗?!似乎是这样。但是使用不同的系统而不是 @SuppressWarnings 似乎真的很奇怪,因为我们通常会这样做来规避 lint 错误。
  • 确实,它只是另一种形式的注释,程序化的方法可以很好地控制运行的内容。
  • 不仅@TargetApi 是多余的,而且仍然无法正确注释您给出的示例:两个注释都不能附加到违规行,因此它们必须附加到整个函数(或if 语句中的代码必须变成 fn)。 Google 为什么要添加@TargetApi?
【解决方案2】:

考虑到这一点将近一年,我想为@Guykun 的回答添加一个小小的补充:

@TargetApi 只会被工具用来告诉开发者“嘿,不要在 XXX android SDK 下使用这个方法”。通常是棉绒。

所以,如果你设计一个像这样的方法:

if (Build.VERSION.SDK_INT > 7){
    //...
}

那么你应该将@TargetApi( 7 ) 添加到你的方法的签名中。

但是,如果您添加 else 语句,并提供一个替代方案,使其适用于所有版本的 Android,例如:

if (Build.VERSION.SDK_INT > 7){
    //...
} else {
    //...
}

那么您应该将@TargetApi( 7 ) 添加到您的方法的签名中。否则,其他开发人员会认为他们无法使用低于 api 级别 7 的方法,但实际上,它也适用于他们。

因此必须使用此注解,用于静态分析,以指示该方法支持的最低 api 级别。如:

@TargetApi( 7 )
public void foo() {
   if (Build.VERSION.SDK_INT > 7){
       //...
   else if (Build.VERSION.SDK_INT > 10){
       //...
   } 
}

更好的是,使用android.Build.VERSION_CODES.* 中定义的常量。

顺便说一句,您会注意到这对于私有方法确实没有用,除了获得更清晰的代码并有助于将来推广该方法。

【讨论】:

  • 这是@Tom 问题的答案。
  • 我想和你一样,但这里是从 Android Studio 的 LoginActivity 向导生成的代码的摘录:@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2) private void showProgress(final boolean show) { if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.HONEYCOMB_MR2) { // ... } else { // ... } }
【解决方案3】:

要在使用针对更高 Api 级别的方法时强制执行 lint 错误,您可以使用 RequiresApi 而不是 TargetApi 并且每当您尝试使用该方法而不检查版本代码时,您都会收到编译错误.

这就是documentation 所说的RequiresApi

这与旧的@TargetApi 注释的目的相似,但是 更清楚地表示这是对调用者的要求, 而不是用于“抑制”方法中的警告 超过 minSdkVersion。

【讨论】:

    猜你喜欢
    • 2014-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-03
    • 2012-11-28
    • 2022-01-17
    • 2020-08-24
    • 2011-03-02
    相关资源
    最近更新 更多