53

我正在编写一个应用程序,它使用了一些仅在最新 API 级别 - 16 中可用的函数和类,但我希望它在 API 级别 15 的设备上运行时没有错误。

让我们举几个例子。一个新的类:Android.widget.Advanceable,和一个新的/重命名的方法View.setBackground()::

我可以做这样的事情:

Advanceable myAdvanceable = ...;

if (android.os.Build.VERSION.SDK_INT >= 16)
{
    myView.setBackground(...);
    myAdvanceable.advance();
}
else
{
    myView.setBackgroundDrawable(...); // The old function name.
    // Don't bother advancing advanceables.
}

如果我将 minSdk 设置为 15,但将构建目标设置为 16(即在 Project Properties->Android 中),它实际上会毫无错误地编译。至少在某些时候。Eclipse 对错误有点随机,有时会说“setBackground() 仅在 API 级别 >= 16 中可用”或类似的,但如果我只是清理项目,这些错误就会神奇地消失。

所以我的问题是,我可以这样做吗?如果我在 API 级别 15 设备上运行它,代码不会崩溃吗?如果它实际上到达 16 代码,它只会崩溃吗?为什么 Eclipse 不阻止我构建它?

编辑 1

感谢您的回答,我想问题应该是:为什么 lint 不会警告我有关使用新 API 的信息?

我的清单中有这个,并且正在使用 API 16 级函数,但它仍然没有警告我:

<uses-sdk android:minSdkVersion="15"
    android:targetSdkVersion="16"/>

此外,我仍然不确定整个类何时是 API 级别的新手,例如Advanceable. 特别是如果我将它们用作成员变量。

编辑 2

答案原来是“Eclipse 是马车”,但 Nico 的回答也很有帮助。

4

3 回答 3

74

内联 Api 错误对 ADT 来说是新的,Eclipse 运行 Lint(我猜可能还有其他东西)来分析您的代码并将这些错误/警告内联。当您有关于优化或最佳实践的警告或提示时,同样适用于 xml 布局。您可以使用注释来抑制类或特定方法中的这些错误。

@TargetApi(16)
@SuppressLint("NewApi")

您在此处放置的示例代码中存在问题,除了 API 级别检查您在代码中是否有一个 Advanceable 实例在 API < 16 中不起作用,因此检查 API 级别仅在您调用新方法时有用,但您不能在 IF 块之外引用新的 API 类。

我发现可以接受的一种方法是创建一个抽象类和两个实现,然后实例化正确的实现,您可以使用带有静态方法的工厂类。

例如,要创建一个在内部使用一些新 API 类和方法的视图,您需要:

1 - 创建抽象类:

public abstract class CustomView {
    public abstract void doSomething();
}
  • 与所有 API 兼容的通用实现
  • 在这里定义抽象方法来拆分实现

2 - 旧版实施

public class CustomLegacyView extends CustomView {
    public void doSomething(){
        //implement api < 16
    }
}
  • 实现 API < 16 的抽象方法

3 - API 16 实施

@TargetApi(16)
public class CustomL16View extends CustomView {

    Advanceable myAdvanceable;

    public void doSomething(){
        //implement api >= 16
    }
}
  • 使用注解@TargetApi(16)
  • 实现 API >= 16 的抽象方法
  • 您可以在此处引用 16 级类(但不能在 CustomView 中)

4 - 工厂级

public class ViewFactory {

    public static CustomView getCustomView(Context context) {

        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            return new CustomL16View(context);
        }else{
            return new CustomLegacyView(context);
        }

    }
}
于 2012-07-21T14:48:45.103 回答
3

使用较新的构建目标并保证将在正确的情况下调用较新的 API 是一种常见的做法。自 ADT 17 以来, Google 甚至添加了@TargetApi()注释,以指定条件加载代码的本地覆盖。

有关更多详细信息,请参阅Lint API 检查

于 2012-07-21T14:08:14.210 回答
-3

1.您拥有Target ApiMinimum SDK属性来定义您的 目标设备类型以及它将在其上运行的最低 Api 版本。

2. Target Api将是应用程序在其上运行的具有完整功能的应用程序,而Minimum SDK将使应用程序在其上运行时有一些妥协,因为较低的 API 版本可能不具有其较高版本中的功能

于 2012-07-21T14:42:18.727 回答