`
lyn111
  • 浏览: 13668 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

Android应用开发之(让你的应用向后兼容)

阅读更多
目前市场上存在多种类型的Android设备,它们运行在不同的SDK版本上。对开发者而言,需要考虑向后兼容性的问题,请问你是想让你的应用在多种设备上运行,还是仅在最新的版本上运行呢?大多情况下,答案应该是前者,你既想使用最新的SDK api ,同时又想支持旧设备。

设置minSdkVersion

如果你在应用中使用了新的api,如录制视频(该功能是 Android 1.5 (API Level 3) 提供的新功能),那你需要在application's manifest 中加入 <android:minSdkVersion>属性,确保你的应用不会在低版本的设备上运行,如:你的应用依赖 最低版本为API Level 3, 你需要指定“3” 作为你的最低的SDK版本:

<manifest>

...

<uses-sdk android:minSdkVersion="3" />

...

</manifest>



然而,有时候你会遇到要使用一个有用的,但不是必须的特性的情况,如在有物理键盘设备上使用软件盘,是否可以通过其他途径使你可以使用新特性而在低版本的设备上使用,又不出错呢?



使用反射

假设你想使用一个新特性如:android.os.Debug.dumpHprofData(String filename). 虽然Debug类在Android1.0已经存在,但是这个方法是在Anroid 1.5 (API Level 3)中新增的,如果你想使用用它,在 Android 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来查看方法,如果成功,使用一个和原来方法一模一样的私有方法来完成调用,模仿原来的方法返回值(如果有)或者抛出异常,示例中的fiddle方法显示了,应用程序如何选择调用新的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);

}

}

在包装类中添加于原始类一样的构造函数与方法,并添加一个静态初始化程序测试新类是否存在,如果NewClass不存在,WrapNewClass会初始化失败,确保包装类不被随意使用,通过方法checkAcailable这种简单的方式进行类初始化,使用方法如下:

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 SDK允许你创建多个不同版本的模拟器,注意不同版本上的差异。
分享到:
评论

相关推荐

    实战Android应用开发-李鸥

    《实战Android应用开发》是李鸥先生的一本深入探讨Android应用程序开发的专业书籍。该书旨在帮助读者通过实际项目案例,掌握Android开发的核心技术,并提升在真实环境中的开发能力。源代码提供给读者一个实践和学习...

    android应用开发基础教程

    4. **安装集成开发环境IDE**:文档中提及了Eclipse,这是早期Android应用开发常用的IDE之一。现代Android开发更多采用Android Studio,它集成了更多的功能,如实时预览、智能代码补全等,能显著提升开发效率。 5. *...

    《C#开发Android应用实战 使用Mono for Android和.NET C#》

    通过这本书,读者不仅可以学习到Android应用开发的基本原理,还能深入理解如何利用C#和.NET的优势来提升开发效率和代码质量。无论你是.NET开发者希望拓宽技能领域,还是对Android开发感兴趣,这本书都是一个不可或缺...

    androidlauncher应用开发完整清晰版

    ### Android Launcher 应用开发知识点概述 #### 一、Launcher应用简介 Launcher是Android系统中的一个关键组件,它为用户提供了一个直观的操作界面,用于启动应用、管理应用图标、快捷方式等。简而言之,Launcher...

    大话企业级Android应用开发实战完整源代码

    在企业级Android应用开发中,我们面临的是更为复杂和严谨的项目需求,这些需求往往涉及到数据安全、系统稳定性、性能优化、多设备兼容性以及高效团队协作等多个方面。"大话企业级Android应用开发实战完整源代码"这个...

    Android应用开发完全自学手册_光盘资料

    《Android应用开发完全自学手册》是一本旨在帮助初学者及有志于深入Android应用开发的读者全面掌握Android开发技能的教程。光盘资料通常包含了书中所提到的源代码示例,便于读者实践和理解。这份资源是学习Android...

    android 应用开发指南 经典教材 CHM格式

    《Android应用开发指南》是一本经典的教材,专为想要学习和精通Android应用开发的程序员而设计。这本书以CHM(Microsoft HTML Help)格式提供,这种格式通常用于电子文档,便于检索和离线阅读。以下是对这本教材核心...

    Android应用开发详解,以及API用法

    在Android应用开发中,开发者需要掌握一系列技术和工具来构建功能丰富的移动应用程序。API(Application Programming Interface)是Android系统的核心组成部分,它提供了与操作系统交互的接口,使得开发者可以调用...

    Android应用开发基础到深入篇_Lesson2_开发环境搭建及HelloWorld2

    在本课程"Android应用开发基础到深入篇_Lesson2_开发环境搭建及HelloWorld"中,我们将探讨Android应用开发的基础,包括如何设置开发环境以及创建第一个"Hello, World!"程序。这一过程对于任何想要踏入Android开发...

    自学android应用开发详细流程经验(第三版)

    自学Android应用开发是一个充满挑战和乐趣的过程,但同时也可能让人感到困惑和迷茫。为了帮助初学者更有效地掌握Android开发,以下是一份详细的学习路径和资源推荐。 首先,基础的Java语法是Android开发的基石。...

    Android开发与应用 全书的PPT课件

    Android Studio是Google官方推荐的集成开发环境(IDE),它包含了编写、调试和打包Android应用所需的所有工具。了解其特性,如布局编辑器、代码自动完成、性能分析等,对提高开发效率至关重要。 3. **Java与Kotlin...

    Android应用开发环境搭建

    "Android应用开发环境搭建" Android 应用开发环境搭建是指在 Android 平台上构建应用程序所需的准备工作,包括安装和配置必要的开发工具、设置编译环境、搭建项目结构等步骤。以下是 Android 应用开发环境搭建的...

    Android应用案例开发大全pdf

    这本书涵盖了广泛的Android应用开发主题,包括基础概念、核心组件、用户界面设计、数据存储、网络通信、多媒体处理以及性能优化等多个方面。 1. **Android基础**:书中首先介绍了Android开发环境的搭建,如安装...

    Android应用开发基础到深入篇_Lesson2_开发环境搭建及HelloWorld1

    在本课程"Android应用开发基础到深入篇_Lesson2_开发环境搭建及HelloWorld1"中,我们将深入了解Android应用开发的起步阶段,包括如何搭建开发环境以及编写第一个"HelloWorld"程序。这不仅是每个Android开发者必备的...

    android手把手教你开发launcher(AndroidStudio版)

    Android Studio是官方推荐的Android应用开发环境,它提供了强大的代码编辑、调试、性能分析以及应用打包功能。在Launcher应用的开发过程中,Android Studio不仅可以帮助开发者快速搭建项目结构,还可以利用其内置的...

    Android应用源码之android Widget小组件开发.zip

    在Android应用开发中,Widget小组件是用户界面的重要组成部分,它们允许用户在主屏幕上与应用程序进行交互,而无需打开实际的应用。本资料包"Android应用源码之android Widget小组件开发.zip"提供了一套完整的源代码...

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

    Lazarus是一款强大的开源集成开发环境(IDE),它基于Free Pascal编译器,为开发者提供了一个免费且...这份指南将帮助开发者快速掌握Lazarus开发Android应用的技巧,无论你是初学者还是有经验的程序员,都能从中受益。

    《Android移动应用开发从入门到精通》.(张魏,李.pdf

    这本书显然是关于Android移动应用开发的教程,从基础入门讲起,逐步深入到精通级别,适合想要学习Android应用开发的读者。 Android移动应用开发是一个涉及多个方面的复杂过程,它包括但不限于以下几个核心知识点: ...

    android应用开发揭秘

    《Android应用开发揭秘》是一本针对Android应用开发者的指南书籍,旨在深入剖析Android操作系统及应用开发的关键概念和实践方法。本书不仅适合初学者,也为有经验的开发者提供了进一步加深理解Android系统的机会。 ...

Global site tag (gtag.js) - Google Analytics