Как поддерживать несколько версий Android в коде?
Получить доступ к контактам в android
android.jar для версий 1.6 имеет People.CONTENT_URI для вызова информации, связанной с контактами, тогда как в более поздних версиях нам нужна поддержка api для RawContacts.CONTENT_URI.
То же самое верно для доступа к календарю, например, поскольку его URI изменяется в android 2.2.
Есть ли наилучшая практика для управления всеми различными изменениями без добавления дополнительного приложения или сборки отдельно для каждой версии изменений?
Ответы
Ответ 1
Совершенно честно, это боль.
Обычно я просто изолирую части кода, которые отличаются друг от друга, и обращаюсь к ним с помощью абстрактных классов. Так технически создавая другую версию для разных ОС.
Но есть и другие способы. Лучшее, что я видел, связано с использованием отражения.
Ответ 2
На мои деньги очень хороший ответ на http://android-developers.blogspot.co.uk/2010/07/how-to-have-your-cupcake-and-eat-it-too.html. Тем не менее, пример немного сложнее, чем нужно, поэтому, основываясь на этом, вот пример того, как справиться с ним при создании уведомлений. Основная причина, по которой это работает, является следствием того, как java-движки интерпретируют классы: она смотрит только на них, когда это необходимо, поэтому, если вы завершаете код определенной версии в классе и создаете его только тогда, когда знаете, что используете эту версию, все это работает...
Есть, насколько я могу судить, два поколения подходов к созданию уведомления и изменение имен по пути во втором. Таким образом, это дает три способа сделать это. Для каждого пути создайте класс с генерацией уведомлений в нем:
Первый подход (используемый до Gingerbread):
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;
}
}
Второй подход, сотовый для 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);
Надеюсь, это поможет!
Ответ 3
Есть много ресурсов, которые вы можете использовать для поддержки нескольких версий Android.
- Прочитайте этот пост в блоге здесь и
затем прочитайте этот здесь, они
поможет вам определить уровень API
версии поддержки.
- Прочитайте это сообщение в блоге по нескольким
поддержки экрана, особенно
иерархия активов при анализе res
папка. Это поможет вам
понимать и разрабатывать, как это сделать
структура папок для поддержки
различные размеры экрана/плотность и
версии для Android.
- Наконец напишите свой собственный ant build
скриптов, чтобы вы могли скомпилировать
все версии андроида.
Ответ 4
- Если вам действительно не нужны новые функции, и действительно нужно поддерживать старые версии Android, оставьте это. Создайте приложение для самой старой версии и не беспокойтесь об этом.
- В другом случае вы можете обнаружить версию с помощью Build и использовать отражение, чтобы загрузить нужные классы. Пример этого можно найти в исходном коде приложения K9Mail
Ответ 5
Там хорошая статья на android.com об этом:
http://developer.android.com/resources/articles/backward-compatibility.html
Лично я бы предложил класс оболочки или решение для библиотеки оберток. Но в малых случаях отражение должно быть хорошим (и в случае, если производительность для вас не проблема).
Если вам нужна дополнительная информация, спросите в комментариях.
Ответ 6
Это отличная статья, когда вам нужно отражать себя в Android (для поддержки нескольких уровней API).
И когда вам нужно иметь разные ресурсы для разных уровней API, это ссылка на использование (см. раздел "Версия платформы (уровень API)" ).
Ответ 7
Если на Eclipse, с версии 11 для ADT, вы можете указать код для запуска с некоторой версией, как описано в Lint API Check.
Кодовое слово @TargetAPI (XX)
Надеюсь, что это поможет
Ответ 8
Лучшая практика (хотя и не для Android, а для J2ME), насколько я знаю, это использование предпроцессорных инструкций типа C/С++, например:
//#if S40
...
//#else
...
//#endif
Некоторые IDE поддерживают такую предварительную обработку, например. Netbeans. Насколько мне известно, в Eclipse есть некоторые плагины, которые также позволяют выполнять предварительную обработку. Я действительно не знаю, применимы ли они для разработки Android. Попробуйте сами Google.