编写向后兼容的 Android 代码

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11592820/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 08:11:37  来源:igfitidea点击:

Writing backwards compatible Android code

androidapicompatibility

提问by Timmmm

I'm writing an app that uses some functions and classes only available in the latest API level - 16, but I want it to run with no errors on devices with API level 15.

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

Let's use a couple of examples. A new class: Android.widget.Advanceable, and a new/renamed method: View.setBackground():

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

I can do something like this:

我可以做这样的事情:

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.
}

And if I set a minSdk of 15 but a build target of 16 (i.e. in Project Properties->Android), it will actually compile with no errors. At least some of the time. Eclipse is a bit stochastic about the errors and will sometimes say "setBackground() is only available in API level >= 16" or similar, but if I just clean the project those errors magically go away.

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

So my question is, am I allowed to do this? Won't the code crash if I run it on an API level 15 device? Will it only crash if it actually gets to the 16 code? Why doesn't Eclipse stop me from building it?

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

Edit 1

编辑 1

Thanks for the answers, I guess the question should really be: Why won't lint warn me about using new APIs?

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

I have this in my manifest, and am using API level 16 functions but it still doesn't warn me:

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

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

Also I'm still not sure about when entire classes are new to an API level, such as Advanceable. Specifically if I use them as member variables.

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

Edit 2

编辑 2

The answer turned out to be "Eclipse is buggy as hell", but Nico's answer was also very helpful.

答案原来是“Eclipse 有很多问题”,但 Nico 的回答也很有帮助。

回答by Nico

Inline Api errors are new to ADT, Eclipse run Lint (and I guess something else maybe) to analyze your code and put those errors / warnings inline. The same apply to xml layout when you have warnings or hints about optimizations or best practices. You can use Annotations to suppress those errors in the class or in a particular method.

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

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

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

There is a problem in the sample code you put here, beside the API level check you have an instance of Advanceable in the code that will not work in API < 16, so checking API level is only useful when you call new methods but you cant reference new API classes outside the IF block.

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

One approach I found acceptable is to create an abstract class and two implementations, then to instantiate the correct implementation you can use a factory class with static methods.

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

For example to create a view that use some new API classes and methods internally you need:

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

1 - Create abstract class:

1 - 创建抽象类:

public abstract class CustomView {
    public abstract void doSomething();
}
  • Common implementation compatible with all APIs
  • Define abstract method here to split implementation
  • 与所有 API 兼容的通用实现
  • 在这里定义抽象方法来拆分实现

2 - Legacy implementation

2 - 遗留实现

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

3 - API 16 implementation

3 - API 16 实现

@TargetApi(16)
public class CustomL16View extends CustomView {

    Advanceable myAdvanceable;

    public void doSomething(){
        //implement api >= 16
    }
}
  • Use annotation @TargetApi(16)
  • implement the abstract method for API >= 16
  • You can reference level 16 classes here (but not in CustomView)
  • 使用注解@TargetApi(16)
  • 实现 API >= 16 的抽象方法
  • 您可以在此处引用 16 级类(但不能在 CustomView 中)

4 - Factory class

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

    }
}

回答by biegleux

It is a common practice to use a newer build target and guarantee newer API will be called in the right circumstances. Google even added @TargetApi()annotation since ADT 17 to specify local overrides for conditionally loaded code.

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

See Lint API checkfor more details.

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

回答by Kumar Vivek Mitra

1.You have Target Apiand Minimum SDKattributes to define what kind of device are you targeting and which will be the least Api versionon which it will run.

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

2.Target Apiwill be the one on which the App runs with Full features, whereas Minimum SDKwill make the App run on it with some Compromises as there can be chances that the lower API version dont have the features which are in its higher versions.

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