【发布时间】:2010-12-29 07:24:21
【问题描述】:
在 android 中访问联系人 1.6 版的 android.jar 具有 People.CONTENT_URI 用于调用联系人相关信息,而在更高版本中,我们需要对 RawContacts.CONTENT_URI 提供 api 支持。
访问日历也是如此,因为它的 URI 在 android 2.2 中发生了更改。
是否有最佳实践来管理所有不同的更改,而无需为每个更改版本添加额外的应用程序或单独构建?
【问题讨论】:
在 android 中访问联系人 1.6 版的 android.jar 具有 People.CONTENT_URI 用于调用联系人相关信息,而在更高版本中,我们需要对 RawContacts.CONTENT_URI 提供 api 支持。
访问日历也是如此,因为它的 URI 在 android 2.2 中发生了更改。
是否有最佳实践来管理所有不同的更改,而无需为每个更改版本添加额外的应用程序或单独构建?
【问题讨论】:
对于我来说,一个很好的答案是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);
希望这会有所帮助!
【讨论】:
老实说,这很痛苦。
我通常只隔离不同的代码部分并使用抽象类访问它们。所以在技术上为不同的操作系统创建不同的版本。
但还有其他方法。我见过的最好的方法是使用反射。
【讨论】:
【讨论】:
在 android.com 上有一篇关于它的好文章: http://developer.android.com/resources/articles/backward-compatibility.html
我个人建议使用包装类或包装类库解决方案。但在小情况下,反射应该没问题(如果性能对您来说不是问题)。
如果您需要更多信息,请在 cmets 中询问。
【讨论】:
This is a great article 用于您必须在 Android 中进行反射(以支持多个 API 级别)时。
当您必须为不同的 API 级别提供不同的资源时,this is the reference to use(请参阅“平台版本(API 级别)”部分)。
【讨论】:
如果在 Eclipse 上,从 ADT 版本 17 开始,您可以指定代码以使用某些版本运行,就像 Lint API Check 中所述。 代码字是@TargetAPI(XX)
希望对你有帮助
【讨论】:
据我所知,最佳实践(虽然不是针对 Android,而是针对 J2ME)是使用预处理 C/C++ 样式的语句,例如:
//#if S40
...
//#else
...
//#endif
一些 IDE 支持这种预处理,例如网豆。据我所知,Eclipse 也有一些插件可以启用预处理。我真的不知道它们是否适用于 Android 开发。尝试自己用谷歌搜索。
【讨论】: