(英语水平有限,翻译的不好请多多指教与谅解)
通过交通运输,消费者可以有机会使用到来自全世界的各种各样的Android设备,在众多的设备中,也运行着不同版本的Android系统平台,一些设备上运行着新版本的系统,一些设备上运行着旧版本的系统。作为一个开发者,在你的应用程序中,需要实现向下兼容――取决于你想在所有设备上运行你的程序,还是只想运行在最新的系统平台上?在有些时候,如果可以兼容较旧版本的设备同时,在支持新版本系统的设备上采用新的API将是有帮助的。
设置最低的Sdk版本
如果使用新的API对应用程序有利――假设你使用Android1.5(API Level 3)中的API刻录视频文件――你应该在应用程序的功能描述文件中添加一个<android:minSdkVersion>标签,来确保你的程序不会被安装在更低版本的设备上。举例说明,如果在你的应用程序中,引用的API 为API Level 3,你应该设置“3”为最低Sdk版本。
<manifest>
...
<uses-sdk android:minSdkVersion="3" />
...
</manifest>
然而,如果你想加入一个实用的但是非必要的特性,就像如果硬件支持的时候在屏幕上弹出一个键盘,你可以允许你的应用使用新的特点,而同时不会在低版本的设备上失去作用(就是指应用程序,在所有的版本的设备上都可以使用,在支持新特性的设备上就可以使用新特性,不支持就不使用)。
使用反射
假设有一个新的函数你想调用,像android.os.Debug.dumpHprofData(String filename)。Debug类在1.0版本中就已经存在了,但是这个方法确实1.5版本才推出的。如果直接调用这个方法,你的应用程序在1.1或者更早的版本上将无法运行。
想要调用这个方法,最简单的做法是通过反射。这需要一次查找然后在Method对象中匹配结果。调用方法通过Method.invoke方法并且不会把结果保存起来,像下面这样:
public class Reflect {
private static Method mDebug_dumpHprofData;
static {
initCompatibility();
};
private static void initCompatibility() {
try {
mDebug_dumpHprofData = Debug.class.getMethod(
"dumpHprofData", new Class[] { String.class } );
/* success, this is a newer device */
} catch (NoSuchMethodException nsme) {
/* failure, must be older device */
}
}
private static void dumpHprofData(String fileName) throws IOException {
try {
mDebug_dumpHprofData.invoke(null, fileName);
} catch (InvocationTargetException ite) {
/* unpack original exception when possible */
Throwable cause = ite.getCause();
if (cause instanceof IOException) {
throw (IOException) cause;
} else if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else if (cause instanceof Error) {
throw (Error) cause;
} else {
/* unexpected checked exception; wrap and re-throw */
throw new RuntimeException(ite);
}
} catch (IllegalAccessException ie) {
System.err.println("unexpected " + ie);
}
}
public void fiddle() {
if (mDebug_dumpHprofData != null) {
/* feature is supported */
try {
dumpHprofData("/sdcard/dump.hprof");
} catch (IOException ie) {
System.err.println("dump failed!");
}
} else {
/* feature not supported, do something else */
System.out.println("dump not supported");
}
}
}
使用了一个静态代码块作为初始化器调用initCompatibility方法,initCompatibility方法做了查找的动作。如果查找成功了,将会调用一个私有的和原来参数、返回值、异常检查都一样的方法。
返回值(如果有返回值)和异常没有被打包,它们以最原始的形式返回。fiddle方法展示了程序在调用新的方法时,根据方法是否存在而做出不同的处理。
对于每一个你想调用的新增的方法,你应该添加一个Method字段,一个静态初始化代码块,并且调用包装后的类。
对于调用一个新的方法来说,这样的实现有点复杂,调用Method.invoke方法也比直接调用方法本身要慢。通过使用包装类,这些问题可以被缓解。
使用包装类
这个思想就是通过一个类把一个已经存在的类或者一个新类,中的新方法包装起来。包装类中的每一个方法,只是通过调用真实的方法并且返回相同的结果。
如果目标类和方法已经存在,直接调用存在的方法就会得到你想要的结果,这时通过包装类这样调用时会有一点点代码重复。如果目标类或者方法不存在,包装类的初始化就会失败,你的应用程序就会知道它应该避免使用新的方法。
假设添加这样一个新的类:
public class NewClass {
private static int mDiv = 1;
private int mMult;
public static void setGlobalDiv(int div) {
mDiv = div;
}
public NewClass(int mult) {
mMult = mult;
}
public int doStuff(int val) {
return (val * mMult) / mDiv;
}
}
我们回为它创建一个包装类:
class WrapNewClass {
private NewClass mInstance;
/* class initialization fails when this throws an exception */
static {
try {
Class.forName("NewClass");
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
/* calling here forces class initialization */
public static void checkAvailable() {}
public static void setGlobalDiv(int div) {
NewClass.setGlobalDiv(div);
}
public WrapNewClass(int mult) {
mInstance = new NewClass(mult);
}
public int doStuff(int val) {
return mInstance.doStuff(val);
}
}
相对于原来的构造方法和方法而言,这有一个方法,提供了一个静态的初始化代码块用来测试新类(NewClass),如果新类不能访问,那么WrapNewClass类的初始化就失败了,证明了包装类不能被使用。checkAvailable方法用来暴力初始化,我们可以这样使用:
public class MyApp {
private static boolean mNewClassAvailable;
/* establish whether the "new" class is available to us */
static {
try {
WrapNewClass.checkAvailable();
mNewClassAvailable = true;
} catch (Throwable t) {
mNewClassAvailable = false;
}
}
public void diddle() {
if (mNewClassAvailable) {
WrapNewClass.setGlobalDiv(4);
WrapNewClass wnc = new WrapNewClass(40);
System.out.println("newer API is available - " + wnc.doStuff(10));
} else {
System.out.println("newer API not available");
}
}
}
如果调用checkAvailable方法成功了,我们知道新的类在系统中存在。如果失败了,我们知道系统中不存在这个类,我们需要调整我们的期望目标。值得注意的是,即使在匹配字节码开始之前调用checkAvailable方法也会失败,如果它不接受一个对不存在的类的引用。这样的代码结构,无论是字节码匹配还是调用Class.forName过程中出异常,结果都是一样的。
当一个已经存在的类增加新方法时,我们包装这个类时,只需要把新方法放在包装类中。直接执行方法即可。包装类中的静态初始化代码块会通过反射执行一次查找操作。
测试是关键
你必须在应用程序想要运行的平台版本上都进行测试。当然,在不同的平台版本上,应用程序的行为可能有所不同。记住这个咒语:如果你没测试过它,他将不会工作。
你可以通过改变模拟器的平台版本来测试你应用程序的向后兼容性。通过创建不同API版本的Android 模拟器,Android SDK 上可以很容易的实现测试。创建了不同的模拟器后,你可以在每个版本的平台上都进行一次测试,来观察有什么不同,在AVD文档中或者通过emulator -help-virtual-device.命令可以查看更多的关于模拟器得信息。
分享到:
相关推荐
Android-Password-Store, Android应用程序与 ZX2C4 命令行 应用程序的兼容 PwdStore 捐赠: 1H1Z1NPTrR5Cej9bKV3Hu4f5WJZYtkbpox的或者比特比特这里应用程序尝试与 pass 兼容 100% 。你可以从以下位置安装应用程序:f...
B.3.1 向Android应用程序关联调试器 B.3.2 终止Android进程 B.3.3 监视Android应用程序的线程活动 B.3.4 监视堆活动 B.3.5 触发垃圾回收(GC) B.3.6 创建和使用HPROF文件 B.4 使用内存分配...
一个快速的起点,使用支持库构建 Material Design android 应用程序以实现向后兼容性。 ##包括 材料支持主题。 整个 BaseActivity,用于轻松创建活动。 一些常用图标(抽屉、设置) ##Usage 只需克隆 repo ...
Android SDK Platform-Tools 是 Android SDK 的一个组件。它包含与 Android 平台进行...虽然这些工具中的某些新功能仅适用于最新版的 Android,但这些工具是向后兼容的,因此您只需要一个版本的 SDK Platform-Tools。
统计语言建模Android应用程序 这是统计语言建模应用程序的Android应用程序组件。 这是一个使用SVG用Java 7编写的Android应用。 SVG除了引起最大的问题外,没有什么好玩的-某些版本的Android默认情况下会启用硬件...
随着网络信息技术的飞速发展,互联网为人们的生活带来了很大的...基于此,本文从Android系统的发展现状着手,分析了Android系统的架构设计,随后探讨了基于Android系统的应用程序的开发。以此来供相关人士交流参考。
其它应用程序——包括你发布的其它程序——需要向系统查询你的应用程序的版本,来确定相互之间的兼容性。 你的应用程序发布的服务可能也需要查询版本来显示给用户。 Android系统自身不检查应用程序的版本信息,也...
Android-Password-Store:与ZX2C4的Pass命令行应用程序兼容的Android应用程序
鉴于此,并结合传统桌面系统上的自动化测试经验,我们在此探讨基于Android平台应用程序的关键字驱动自动化测试的可能性,并摸索一条适合在移动应用开发过程日新月异的现实情况中切实有效的实施自动化测试的方法。
android实在获得root权限应用静默安装
android-support-v7 android v7 应用程序兼容
这是我在学习android定位服务和google map API的过程中开发的简单android应用程序。 该应用程序获取您的当前位置并在地图中显示。 用户可以标记他们的位置,并可以向其添加地理围栏警报。 此应用程序还使用Android...
Keep It Native 提供与原生应用程序一样的所有功能,具有高度可定制性、兼容性和强大的共享功能。 解析通知系统包括简单的文本通知或链接通知模式:现在您可以在通知上发送可定制的内容,即优惠、折扣等。当用户...
机器人漫游者使用控制由 MC33926 电机屏蔽驱动的 Arduino 漫游车的 Android 嵌入式应用程序。 第一个原型是使用原型开发板开发的。外部依赖(Gradle/Maven Android 库) 简化 Twitter 访问的外部用于漫游车控制的...
丛 消除了对在Google离线设备上Android应用程序兼容性的担忧。 该项目已获得CC0 V1许可证的许可。说明Google Play服务是大多数Android设备不可或缺的一部分,它使用户能够在手机上使用其Google帐户,并为依赖于它们...
自己整理的Android12版本的系统资源目录分析,包括各个目录对应的分支 ...frameworks:应用程序框架,Android系统核心部分,由Java和C++编写.pdf packages:应用程序包.pdf system:底层文件系统库、应用和组件.pdf
* 兼容android,ios、微信小程序、h5 * 已完成页面:首页、分类页、购物车页、发现页、我的页、评论(列表页、新增页、追评页、评价物流页、详情页)、地址(列表页、新增暨修改页、国家地区选择页)、设置、商品...
Android 项目是使用 Android 操作系统和相关开发工具开发的一款移动应用程序。Android 平台提供了丰富的功能和接口,开发人员可以使用 Java 或 Kotlin 等编程语言编写 Android 应用程序。Android 项目也可以是针对...