如何在您的代码中支持多个Android版本?

时间:2010-12-29 07:24:21

标签: java android

访问android中的联系人 版本1.6的android.jar有People.CONTENT_URI用于调用联系人相关信息,而在以后的版本中我们需要对RawContacts.CONTENT_URI提供api支持。

例如,因为它在Android 2.2中更改了URI,所以访问日历也是如此。

是否有最佳做法来管理所有不同的更改,而无需为每个版本的更改添加额外的应用程序或单独构建?

8 个答案:

答案 0 :(得分:13)

对于我的钱,一个非常好的答案是http://android-developers.blogspot.co.uk/2010/07/how-to-have-your-cupcake-and-eat-it-too.html。但是,这个例子比需要的要复杂得多,所以基于此,这里有一个如何在构建通知时处理它的例子。这种工作的根本原因是java引擎如何解释类​​的结果:它只在需要时查看它们,所以如果你在类中包装特定于版本的代码并且只在你知道使用该版本时才创建它,那么它都可以工作...

据我所知,有两代创建通知的方法,以及第二代中的命名更改。这样就有三种方法可以做到。对于每种方式,创建一个包含通知生成的类:

第一种方法(用于姜饼):

public class MyNotificationBuilderToGingerBread {
Notification notification = null;

MyNotificationBuilderToGingerBread(Context myContext, int icon, String ticker, String title, String info, Long timeStamp, PendingIntent pendingIntent, int flags) {
    notification = new Notification(R.drawable.ic_sb, ticker, timeStamp);
    notification.setLatestEventInfo(myContext, title, info, pendingIntent);
    notification.flags |= flags;        
}

Notification get() {
    return notification;
}
}

第二种方法,Honeycomb to IceCreamSandwich:

public class MyNotificationBuilderHoneyCombToIceCreamSandwich {
Notification.Builder mb = null;

MyNotificationBuilderHoneyCombToIceCreamSandwich(Context myContext, int icon, String ticker, String title, String info, Long timeStamp, PendingIntent pendingIntent, boolean onGoing) {
    mb = new Notification.Builder(myContext);
    mb.setSmallIcon(icon);
    mb.setContentIntent(pendingIntent);
    mb.setContentTitle(title);
    mb.setContentText(info);
    mb.setWhen(timeStamp);
    if (ticker != null) mb.setTicker(ticker);       
    mb.setOngoing(onGoing);
}

Notification get() {
    return mb.getNotification();
}   
}

第二代,改名为Jellybean(到目前为止......):

public class MyNotificationBuilderJellyBean {

Notification.Builder mb = null;

MyNotificationBuilderJellyBean(Context myContext, int icon, String ticker, String title, String info, Long timeStamp, PendingIntent pendingIntent, boolean onGoing) {
    mb = new Notification.Builder(myContext);
    mb.setSmallIcon(icon);
    mb.setContentIntent(pendingIntent);
    mb.setContentTitle(title);
    mb.setContentText(info);
    mb.setWhen(timeStamp);
    if (ticker != null) mb.setTicker(ticker);       
    mb.setOngoing(onGoing);
}

Notification get() {
    return mb.build();
}   
}

然后,您只需要选择要实时实例化的类:

// System information
private final int sdkVersion = Build.VERSION.SDK_INT;
// If you want to go really old:
    // (actually, there is a question about how this issue should be handled
    // systematically. Suggestions welcome.)
// final int sdkVersion = Integer.parseInt(Build.VERSION.SDK);

    // This is for a permanent notification. Change the final argument (flags or boolean) if it isn't meant ot be
    // For meaning of other variable, see notification documentation on the android website.
    if (sdkVersion < Build.VERSION_CODES.HONEYCOMB) {
        MyNotificationBuilderToGingerBread mnb = new MyNotificationBuilderToGingerBread(myContext, R.drawable.notification_icon, ticketText, title, infoText, timeStampMillis, pendingIntentForTapOnFullNotitifcation, Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR);
        notification = mnb.get();
    }
    else if (sdkVersion < Build.VERSION_CODES.JELLY_BEAN) {
        MyNotificationBuilderHoneyCombToIceCreamSandwich mnb = new MyNotificationBuilderHoneyCombToIceCreamSandwich(myContext, R.drawable.notification_icon, ticketText, title, infoText, timeStampMillis, pendingIntentForTapOnFullNotitifcation, true);
        notification = mnb.get();
    }
    else {
        MyNotificationBuilderJellyBean mnb = new MyNotificationBuilderJellyBean(myContext, R.drawable.notification_icon, ticketText, title, infoText, timeStampMillis, pendingIntentForTapOnFullNotitifcation, true);
        notification = mnb.get();
    }

    // Send the notification.
    notificationManager.notify(idForNotificationManager, notification);

希望这有帮助!

答案 1 :(得分:8)

有许多资源可供您用来帮助支持多个版本的Android。

  1. 阅读此博文here和 然后阅读这一个here,他们 将帮助您解决API级别问题 版本支持问题。
  2. 阅读多篇文章的this博文 屏幕支持,特别是如何 在res中解析的资产层次结构 夹。这会对你有所帮助 了解并设计如何做 资产文件夹结构支持 不同的屏幕尺寸/密度和 Android版本。
  3. 最后编写自己的自定义ant构建 脚本,以便您可以编译 所有版本的android。

答案 2 :(得分:5)

相当诚实,这是一种痛苦。

我通常只是隔离不同的代码部分并使用抽象类访问它们。因此,在技术上为不同的操作系统创建不同的版本。

但还有其他方法。我见过的最好的一个涉及使用反射。

答案 3 :(得分:2)

  • 如果你真的不需要新的功能,并且真的必须支持旧的Android版本,请删除它。为最旧版本构建应用程序,不要为这种事情烦恼。
  • 在另一种情况下,您可以使用Build检测版本,并​​使用反射来加载所需的类。可以在source code of the K9Mail app
  • 中找到相关示例

答案 4 :(得分:1)

在android.com上有一篇很好的文章: http://developer.android.com/resources/articles/backward-compatibility.html

我个人建议使用包装器类或包装器库解决方案。但在小的情况下,反射应该很好(如果性能不是你的问题)。

如果您需要更多信息,请在评论中提问。

答案 5 :(得分:1)

This is a great article用于在Android中进行反射时(支持多个API级别)。

当您必须为不同的API级别设置不同的资源时,this is the reference to use(请参阅“平台版本(API级别)”部分)。

答案 6 :(得分:1)

如果在Eclipse上,从ADT版本17开始,您可以像Lint API Check中所述,使用某个版本指定运行代码。 代码字是 @TargetAPI(XX)

希望有所帮助

答案 7 :(得分:0)

据我所知,最佳实践(虽然不适用于Android,但适用于J2ME)是使用预处理C / C ++样式语句,如:

//#if S40
    ...
//#else
    ...
//#endif

某些IDE支持这种预处理,例如: Netbeans的。据我所知,Eclipse有一些插件可以启用预处理。我真的不知道它们是否适用于Android开发。尝试谷歌自己。