`
Beyon_javaeye
  • 浏览: 66862 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

应用程序后向兼容

阅读更多
应用程序后向兼容
  在全世界,现在人们手里有着各种各样的基于Android的设备。而这些设备中,有很多种Android平台的版本在使用,一些运行着最新版平台,而另一些还在运行着老的版本。作为一名开发人员,你需要考虑你的应用程序是否支持后向兼容——你想你的应用程序能在所有的设备上运行吗,或是只是在最新的平台上运行?在某些情况下,在支持的设备上部署新的API,并支持老的设备是很有用的。
设定minSdkVersion
  如果一个新的API的使用对应用程序来说是不可或缺的——也许,你需要使用在Android 1.5(API等级3)中引入的视频录制API——你需要在应用程序的manifest文件中添加<android:minSdkVersion>结点,来确保应用程序不会安装到老的设备上。例如,如果你的应用程序依赖于API 等级3中引入的API,那么,你需要指定“3”作为最低的SDK版本:
<manifest>
   ...
   <uses-sdk android:minSdkVersion="3" />
   ...
</manifest>

  然而,如果你想添加一个有用的但不是必须的特性时,例如在硬件键盘可用的时候弹出一个屏幕键盘,你可以这样书写你的代码:允许你的程序使用新的特征,而在老的设备上不会失败。
使用反射
  假设你想使用android.os.Debug.dumpHprofData(String filename)这个新的方法。Debug这个类自从Android 1.0的时候就已经存在了,但这个方法在Android 1.5(API等级3)中才新增的。如果你想直接调用它,那么,在Android 1.1或更早的设备上,你的app将运行失败。
  最简单的方式是通过反射的方式来调用这个方法。这需要做一次查找并在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,进行方法的查找。如果查找成功的话,使用一个私有的方法(与原始的函数签名一致——参数,返回值、异常检查)来替换方法的调用。返回值(如果有的话)和异常都如同原始的方法一样进行返回。fiddle方法演示了程序的选择逻辑,是调用新的API还是在新API无效的情况下作其它的事情。
  对于每个你想调用的方法,你可能要添加一个额外的私有Method字段,字段初始化方法,和对调用的包装方法。
  如果想调用一个之前未定义的类的方法的话,就比较复杂了。并且,调用Method.invoke()比直接调用这个方法要慢很多。这种情况可以通过一个包装类来缓和一下。
使用包装类
  想法是创建一个新的类,来包装新的或已经存在的类暴露出来的所有的新API。包装类中的每个方法只是调用相应的真实方法并返回相同的结果。
  如果目标类和方法存在的话,能得到与直接调用相同的行为,并有少量的性能损失。如果目标类或方法不存在的话,包装类的初始化会失败,并且你的应用程序知道必须避免使用这些新的方法。
  假设这个类是新增的:
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);
   }
}

  包装类拥有和原始类一模一样的方法和构造函数,加上一个静态的初始化方法和测试方法来检查新类是否存在。如果新类不可获得的话,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的调用抛出异常。
  当包装一个有新方法的已存类时,你只需要在包装类中添加新的方法。老的方法直接调用。新的方法需要在WrapNewClass的静态初始化方法中作一次反射检查。
测试是关键
  你必须测试任何想支持的Android框架版本。一般来说,应用程序在不同的版本上行为不同。记住一条法则:如果你不尝试,它就不能工作。
  你可以在老版本平台的模拟器上运行应用程序来测试程序的后向兼容性。由于可以创建不同API等级的“虚拟设备”,因此,你可以很容易地进行测试。一旦你创建了AVD,你就可以在新老版本系统上进行程序测试,也许你还可以一边测试一边观察它们的不同点。更多关于模拟器/虚拟设备的信息,请参考AVD documentation和运行emulator -help-virtual-device命令。
分享到:
评论

相关推荐

    sql2005向后兼容组件32位/64位

    SQL Server 2005 向后兼容组件是微软为确保旧版应用程序能在新版本的SQL Server上运行而设计的一套工具集。这些组件能够帮助用户在更新到更高版本的SQL Server时,继续支持那些基于SQL Server 2005构建的应用程序。...

    Win 2003 x64操作系统-IIS兼容32位应用程序-解决方案

    在Windows Server 2003 x64操作系统中,IIS (Internet Information Services) 默认配置为支持64位应用程序,但遇到与32位应用程序不兼容的问题时,开发者和管理员可能面临困境。这种情况通常出现在尝试运行在32位...

    SQL Server 2005向后兼容组件包32或64位

    SQL Server 2005 向后兼容组件包是针对那些仍需在较新系统上运行基于 SQL Server 2005 应用程序的用户设计的。这个组件包提供了必要的支持,使得2005版的应用能在更新的操作系统环境下正常工作。此包分为32位(x86)...

    weblogic不兼容客户端的解决办法

    但是在实际应用中,有些 HTTP 客户端在与 WebLogic 服务器下面的 Web 程序交互时,可能会出现不兼容的问题。这主要是因为 WebLogic 服务器使用 chunked 编码传输数据,而一些客户端可能不支持这种编码方式,导致数据...

    商业客户端部署系列之六:应用程序兼容 4.0”概述

    在“商业客户端部署系列之六:应用程序兼容 4.0”的主题中,我们主要探讨的是在企业环境中如何确保各种应用程序能够在新的操作系统或更新的技术平台上顺利运行。这涉及到一系列技术和策略,旨在减少因软件升级或迁移...

    介绍了向前兼容和向后兼容的概念

    向后兼容则相反,指的是较新版本的系统或应用程序能够识别并处理由其旧版本创建的数据或格式。即新版本可以理解旧版本的内容。例如,新版本的软件能够打开和读取旧版本的文件格式。向后兼容的主要目标是为了确保新...

    天敏U盒系列应用程序

    5. 兼容性检查:为了确保在不同系统上的稳定运行,应用程序可能有兼容性检测机制,检查并解决可能存在的系统冲突问题。 6. 用户界面友好:天敏U盒系列应用程序可能设计有直观易用的用户界面,使用户能轻松完成各项...

    解除windows 64位系统对32位应用程序的内存限制

    在Windows 64位操作系统中,32位应用程序默认受到内存使用量的限制,这是由于系统设计时的兼容性和性能考虑。通常,32位程序在64位系统上最多只能访问约4GB的虚拟内存,尽管实际硬件可能提供更多的资源。这个限制...

    Windows Vista 产品兼容性(3):创建稳健的应用程序

    应用程序兼容性模式 了解并利用Vista的兼容性模式,允许应用程序以早期Windows版本的兼容性模式运行,可以帮助解决一些不兼容的问题。 ### 9. 更新和维护 保持应用程序的更新和维护是确保长期兼容性的关键。定期...

    reg236兼容程序

    在Windows操作系统中,注册表是存储系统和应用程序设置的关键数据库。当用户安装新软件、硬件驱动或更新操作系统时,可能会遇到兼容性问题,此时就需要这类工具来修复或调整注册表设置,以确保软件正常运行。 描述...

    Android-Password-Store, Android应用程序与 ZX2C4 命令行 应用程序的兼容.zip

    Android-Password-Store, Android应用程序与 ZX2C4 命令行 应用程序的兼容 PwdStore 捐赠: 1H1Z1NPTrR5Cej9bKV3Hu4f5WJZYtkbpox的或者比特比特这里应用程序尝试与 pass 兼容 100% 。你可以从以下位置安装应用程序:f...

    计算器源代码和应用程序

    其次,"应用程序"指的是编译或解释源代码后生成的可执行文件。在这个压缩包中,"计算器4.0.exe"就是一个已经编译好的应用程序,用户可以直接运行而无需知道其背后的源代码。这个文件是二进制格式,用于计算机直接...

    实现往linux上应用程序迁移的报告

    在Linux系统中,迁移不仅仅是确保应用程序能够运行,还需要全面测试其与Linux系统的兼容性,并处理移植后可能出现的问题。 【标签】:“应用程序迁移”“Linux” 【正文】: Linux操作系统是一种开源、免费的类...

    32位应用程序在IA-64_Linux上兼容性的实现与测试.pdf

    在实现IA-64_Linux平台上的32位应用程序兼容性时,需要解决两个关键问题:一是转换IA-32指令到IA-64指令,二是实现Translation Layer(TL)层。TL层是一个译码器,负责将IA-32指令转换为相应的IA-64指令,然后与本来...

    CAD:应用程序的组件中发生了未处理的异常

    在CAD(计算机辅助设计)领域,"应用程序的组件中发生了未处理的异常"是一个常见的错误提示,这通常意味着在运行CAD软件时,遇到了一个程序无法正常处理的问题,导致了系统崩溃或者异常中断。这种情况可能由多种因素...

    关闭Win7程序兼容性助手

    然而,在某些情况下,它可能会导致系统运行缓慢或者干扰某些应用程序的正常运行。因此,了解如何关闭Win7程序兼容性助手对于优化系统性能和提升用户体验具有重要意义。 ### 关闭Win7程序兼容性助手的两种方法 ####...

    Win10程序属性没有兼容性选项怎么解决 Win10程序属性没有兼容性选项解决方法.docx

    2. 在本地组策略编辑器窗口中,展开至“计算机配置” &gt; “管理模板” &gt; “Windows 组件” &gt; “应用程序兼容性”。 3. 在右侧找到“删除程序兼容性属性页” 정책,并双击打开。 4. 将其设置为“未配置”,然后点击...

    win8上怎么运行不兼容的应用程序?.docx

    在Windows 8操作系统中,有时候会遇到一些应用程序由于与新系统不兼容而无法直接运行的问题。这通常是由于软件开发商尚未发布适用于新系统的更新版本。不过,通过一些设置和技巧,我们仍然可以在Windows 8上运行那些...

    应用程序无法正常启动0xc000007b解决办法

    0xc000007b错误通常与应用程序的兼容性或系统组件的损坏有关。下面我们将详细探讨这个问题的原因、影响以及解决方案。 **错误原因:** 1. **不兼容的软件版本**:如果应用程序是为不同架构(例如32位或64位)的...

Global site tag (gtag.js) - Google Analytics