【问题标题】:Writing backwards compatible Android code编写向后兼容的 Android 代码
【发布时间】:2012-07-20 12:36:30
【问题描述】:

我正在编写一个应用程序,它使用了一些仅在最新 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 的回答也很有帮助。

【问题讨论】:

  • 您使用的是什么版本的 ADT?
  • 如果您打开了 NewApi 检查,请检查 Chinaski 编辑的答案,清理您的项目,右键单击它并选择 Android 工具 > 运行 Lint:检查常见错误。
  • 如果“保存文件时,检查错误”和“导出应用程序时运行完整的错误检查...”这两个复选框都被选中,请参见 Lint 错误检查选项卡。
  • 是的,我将 NewApi 设置为错误,并且设置了“保存文件时...”和“运行完整的错误检查...”复选框。大多数时候它仍然没有运行 lint。但它偶尔确实为我正在编辑的文件运行它(直到我保存它)。看起来像是 Eclipse 中的一个错误,这是人类已知的最错误的 IDE。

标签: android api compatibility


【解决方案1】:

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

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

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

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

    }
}

【讨论】:

  • 只是为了明确注释,如@TargetApi(16) 不会影响运行时弹出,只需告诉 eclipse 你的目标是 api 16 并且不想看到 lint 错误。无论如何,在 api
  • +1 好答案。另外,我建议使用Build.VERSION_CODES.JELLY_BEAN 而不是硬编码16
  • 不错的答案,但是 View 的示例有点误导,因为如果您希望在 XML 中定义 UI(并且您应该希望这样),您就不能真正使用 Factory 那里: )。代替工厂可以使用layout-v16-like folders
【解决方案2】:

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

更多详情请见Lint API check

【讨论】:

    【解决方案3】:

    1.你有Target ApiMinimum SDK属性来定义你是什么类型的设备 定位,它将是最低的 Api 版本,它将在其上运行。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-10
      • 1970-01-01
      • 2012-03-22
      • 2019-01-13
      • 1970-01-01
      相关资源
      最近更新 更多