编写向后兼容的Android代码

时间:2012-07-21 13:58:51

标签: android api compatibility

我正在编写一个使用仅在最新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的回答也非常有用。

3 个答案:

答案 0 :(得分:74)

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

@TargetApi(16)
@SuppressLint( “NewApi”)

您在此处放置的示例代码中存在一个问题,除了API级别检查外,您在代码中有一个不能在API中使用的Advanceable实例&lt; 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的抽象方法&lt; 16

3 - API 16实施

@TargetApi(16)
public class CustomL16View extends CustomView {

    Advanceable myAdvanceable;

    public void doSomething(){
        //implement api >= 16
    }
}
  • 使用注释@TargetApi(16)
  • 实现API的抽象方法&gt; = 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);
        }

    }
}

答案 1 :(得分:3)

通常的做法是使用较新的构建目标,并保证在适当的情况下调用较新的API。 Google甚至在ADT 17后添加了@TargetApi()注释,以指定有条件加载代码的本地覆盖。

有关详细信息,请参阅Lint API check

答案 2 :(得分:-2)

1。您有Target ApiMinimum SDK属性来定义您的设备类型        定位,以及将运行的最少Api版本

2。 Target Api将是应用以完整功能运行的应用,而Minimum SDK将使应用使用一些Compromises运行它,因为较低的API版本可能没有更高版本的功能