`
LoveZhou
  • 浏览: 272397 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Android 应用程序的向后兼容(译)

阅读更多
(英语水平有限,翻译的不好请多多指教与谅解)
通过交通运输,消费者可以有机会使用到来自全世界的各种各样的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.命令可以查看更多的关于模拟器得信息。
0
0
分享到:
评论

相关推荐

    Android应用程序开发

    ### Android应用程序开发知识点详解 #### 一、Android概述 Android是一种基于Linux内核的开源移动设备操作系统,由Google公司和开放手机联盟领导及开发。它主要用于触摸操作的手持设备上,如智能手机和平板电脑等...

    android应用程序开发

    在本文中,我们将深入探讨如何进行Android应用程序开发,特别是针对手机通信录的实现。这个项目旨在创建一个功能齐全的通信录应用,用户可以添加、删除、编辑联系人,查看联系人列表,以及直接拨打电话和发送短信给...

    android应用程序 宅男志全集

    《Android应用程序:宅男志全集》是一款专为Android用户设计的应用程序集合,包含了多个版本的宅男志及相关图库应用。这个应用合集显然深受宅文化爱好者的欢迎,其多版本的提供显示了开发者对产品不断更新和完善的...

    android应用程序小例子

    在Android应用程序开发中,我们经常会遇到各种各样的小例子,这些例子可以帮助开发者更好地理解和掌握Android SDK中的各种功能和API。本篇文章将详细探讨"android应用程序小例子"这一主题,涵盖从基础概念到实际应用...

    Lazarus开发Android应用程序指南(2017新版)第一部分

    本指南将详细介绍如何使用Lazarus来开发Android应用程序,特别关注2017年更新版的新特性与优化。 在2017年的版本中,Lazarus为Android开发带来了一系列改进,包括更好的兼容性、优化的性能以及更多的组件支持。首先...

    Android应用程序概述

    Android应用程序概述 Android操作系统是目前全球最流行的移动设备操作系统之一,尤其在智能手机和平板电脑市场占据了主导地位。Android系统以其开放源代码、丰富的定制性和强大的开发者社区为特点,吸引了无数用户...

    《Android应用程序开发与典型案例》完整版PDF

    《Android应用程序开发与典型案例》是一本深入探讨Android应用开发的专业书籍,它涵盖了从基础到高级的各类主题,旨在帮助开发者全面掌握Android平台上的应用构建技巧。这本书提供了丰富的案例,通过实例解析来阐述...

    基于Android的移动终端应用程序开发与研究.pdf

    2. 兼容性:Android应用程序需要在不同的Android版本和不同的移动终端设备上运行,开发者需要确保应用程序的兼容性。 3. 用户体验:Android应用程序的用户体验是非常重要的,开发者需要确保应用程序的用户体验。 ...

    Android 小应用程序

    NotePad是一个基础的、用于记录和管理简单文本笔记的应用,它是Android开发初学者常用来学习和理解Android应用程序框架的实例。 在Android开发中,NotePad应用展示了以下几个关键知识点: 1. **Activity**:...

    Android网站应用程序源码

    总之,这个【Android网站应用程序源码】项目涵盖了Android应用开发的基础知识,包括使用IDE(NetBeans)、Android SDK、WebView组件、网络请求以及数据解析等。对于想要深入理解Android应用开发,尤其是如何构建一个...

    Android应用程序中文教材

    【Android 平台简介】 ...总结来说,"Android 应用程序中文教材" 提供了详尽的指南,帮助初学者建立基于 Eclipse 的开发环境,并深入了解 Android 平台的特性和优势,为踏入 Android 开发领域打下坚实基础。

    Android应用程序开发研究与应用.pdf

    【Android应用程序开发研究与应用】 本文主要探讨了Android应用程序的开发技术及其应用,作者李嘉诚从基础到实践,详细阐述了Android平台及其开发过程。Android是由Google公司推出的开源操作系统,由于其开放性和...

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

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

    Android应用程序开发宝典

    ### Android应用程序开发宝典知识点概览 #### 一、Android系统及开发环境搭建 ##### 1.1 Android系统概述 - **定义与历史**: Android是由Google公司开发的基于Linux内核的操作系统,最初由Andy Rubin创立,旨在为...

    用Eclipse开发Android应用程序[整理].pdf

    Eclipse 开发 Android 应用程序 Android 是一种针对移动平台的开放源码操作系统, Google 引入了 Android,并在短时间内获得了市场的关注。 Android 不仅仅是另一种包含电话、菜单和触摸屏功能的移动平台,而是一种...

    android应用程序安装工具

    Android应用程序安装工具是一款专为Android系统设计的便捷软件,它能够帮助用户轻松地在设备上安装APK文件。这款工具采用C#编程语言编写,因此需要用户计算机上预先安装.NET Framework,这是一个由微软开发的运行时...

    15枚精美的 Android 应用程序图标PNG格式素材

    2. **Android应用程序图标设计**:在Android平台,应用图标不仅要在主屏幕上显示,还可能出现在通知栏、设置菜单等多个地方。因此,图标设计需要考虑不同尺寸的需求,包括launcher图标(启动器图标)、小图标(例如...

    Android应用程序开发真机环境的实现.pdf

    安装配置完成后,就可以进行Android应用程序的开发和调试。 对于Android应用程序开发而言,调试是完成开发过程的重要一步。以往,开发者多依赖Android模拟器进行调试,但模拟器由于功能限制和兼容性问题,无法完全...

    让Qt应用程序跑在Android上

    Qt作为一款强大的跨平台开发框架,其灵活性和兼容性使得开发者能够轻松地将应用程序部署到多种操作系统上,包括Android。这为C++开发者打开了进入移动平台的大门,无需掌握Java,也能进行Android应用开发。 在...

Global site tag (gtag.js) - Google Analytics