侧边栏壁纸
博主头像
翻斗

开始一件事最好是昨天,其次是现在

  • 累计撰写 44 篇文章
  • 累计创建 42 个标签
  • 累计收到 3 条评论

Android import高版本api不会在低版本中报错

翻斗
2015-04-01 / 0 评论 / 0 点赞 / 1,186 阅读 / 1,650 字

例如,5.0以上才有的查看应用使用情况的api,在某个类中,我们先
import android.app.usage.UsageEvents.Event;

然后有个方法

public static List<UsageStats> getUsageStatsList(Context context) {
List<UsageStats> usageStatsList = null; 
try {
 UsageStatsManager usm = getUsageStatsManager(context);  
      Calendar calendar = Calendar.getInstance();  
    long endTime = calendar.getTimeInMillis(); 
      calendar.add(Calendar.MONTH, -1);  
    long startTime = calendar.getTimeInMillis();
     usageStatsList = usm.queryUsageStats(
  UsageStatsManager.INTERVAL_DAILY, startTime, endTime);
} catch (Exception ex) {

}  
     return usageStatsList;
}

这个apk用api 22编译通过,打包成apk,没问题。

然后在5.0以上手机运行,没问题。

如果子5.0以下的,比如4.2.2手机上

  • 一开始,ClassLoader载入这个class,发现了一个当前没有的东西,dalvikvm就会警告【注意是警告,warning,不是error,因此不会崩溃】找不到类或者方法,NoSuchMethodError or ClassNotFoundException

  • 如果你没有判断api level就直接执行上述方法,那么就会报错,这个时候就是Exception了,导致应用程序崩溃。这个时候的处理办法其实很多人都知道,就是判断Build.VERSION.SDK_INT >= 21之后再调用方法

其实我想有些人可能跟我之前想法一样,认为载入class的时候,【执行import语句发现没有对应api就报错】,其实这是下意识的这么认为,仔细想想java class的构造,或者看看简单smali文件,就应该知道,其实class中根本就没有所谓的import语句,这个只是方便用户编写的,真正class中的,都是绝对路径

看个简单例子(不知道哪儿的一个被我曾反编译过的):

.class final Lcom/flurry/android/a;
.super Ljava/lang/Object;
.source "SourceFile"


# instance fields
.field a:Ljava/lang/String;

.field b:J

.field c:Ljava/lang/String;

.field d:Ljava/lang/String;

.field e:Landroid/os/Handler;


# direct methods
.method constructor <init>()V
    .locals 0

    .prologue
    .line 6
    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
    return-void
.end method

所以说,根本不会出现什么执行import语句导致找不到类报错的现象(Eclipse作为IDE只是根据编译版本来拒绝你编译而已)。

在IDE中import了一个新版本的api,eclipse报错了,没关系,把编译的android target调整为对应api版本就行,Eclipse中是修改project.properties将里面的target一栏改下,比如上面的5.0以上才有的api, 刚开始我用的target 19会提示报错,改为 target=android-22 就可以了,然后注意在真正调用的地方处理好SDK_INT判断逻辑即可。

0

评论区