Запись обратно совместимого кода Android
Я пишу приложение, которое использует некоторые функции и классы, доступные только на последнем уровне API - 16, но я хочу, чтобы он запускался без ошибок на устройствах с уровнем API 15.
Позвольте использовать несколько примеров. Новый класс: Android.widget.Advanceable
и новый/переименованный метод: View.setBackground()
:
Я могу сделать что-то вроде этого:
Advanceable myAdvanceable = ...;
if (android.os.Build.VERSION.SDK_INT >= 16)
{
myView.setBackground(...);
myAdvanceable.advance();
}
else
{
myView.setBackgroundDrawable(...); // The old function name.
// Don't bother advancing advanceables.
}
И если я установил minSdk из 15, но цель построения 16 (т.е. в Project Properties → Android), он фактически скомпилируется без ошибок. По крайней мере, некоторое время. Eclipse немного стохастичен в отношении ошибок и иногда говорит: "setBackground() доступен только в уровне API >= 16" или аналогичном, но если я просто очищу проект, то эти ошибки волшебным образом исчезнут.
Итак, мой вопрос: разрешено ли мне это делать? Не будет ли сбой кода, если я запустил его на устройстве уровня 15 API? Будет ли это только сбой, если он действительно доберется до 16 кода? Почему Eclipse не останавливает меня от его создания?
Изменить 1
Спасибо за ответы, я думаю, вопрос действительно должен быть: почему я не буду предупреждать меня об использовании новых API?
У меня это в моем манифесте, и я использую функции уровня API 16, но он все равно меня не предупреждает:
<uses-sdk android:minSdkVersion="15"
android:targetSdkVersion="16"/>
Также я все еще не уверен, когда целые классы являются новыми для уровня API, например Advanceable
. В частности, если я использую их как переменные-члены.
Изменить 2
Ответ оказался "Eclipse багги, как ад", но ответ Нико также очень помог.
Ответы
Ответ 1
Ошибки Inline Api являются новыми для ADT, Eclipse запускают Lint (и я думаю, что-то еще возможно), чтобы проанализировать ваш код и поместить эти ошибки/предупреждения в строку. То же самое относится к макету xml, когда у вас есть предупреждения или подсказки об оптимизации или передовой практике. Вы можете использовать аннотации для подавления этих ошибок в классе или в определенном методе.
@TargetApi (16)
@SuppressLint ( "NewApi" )
В приведенном здесь примере кода есть проблема, помимо проверки уровня API у вас есть экземпляр Advanceable в коде, который не будет работать в API < 16, поэтому проверка уровня API полезна только при вызове новых методов, но вы не можете ссылаться на новые классы API вне блока IF.
Один из подходов, который я нашел приемлемым, заключается в создании абстрактного класса и двух реализаций, а затем для создания правильной реализации вы можете использовать класс factory со статическими методами.
Например, для создания представления, которое использует некоторые новые классы и методы API внутри, вам необходимо:
1 - Создать абстрактный класс:
public abstract class CustomView {
public abstract void doSomething();
}
- Общая реализация, совместимая со всеми API-интерфейсами
- Определите абстрактный метод здесь, чтобы разделить реализацию.
2 - Унаследованная реализация
public class CustomLegacyView extends CustomView {
public void doSomething(){
//implement api < 16
}
}
- реализовать абстрактный метод для API < 16
3 - реализация API 16
@TargetApi(16)
public class CustomL16View extends CustomView {
Advanceable myAdvanceable;
public void doSomething(){
//implement api >= 16
}
}
- Использовать аннотацию @TargetApi (16)
- реализовать абстрактный метод для API >= 16
- Здесь вы можете ссылаться на классы уровня 16 (но не в CustomView).
4 - factory класс
public class ViewFactory {
public static CustomView getCustomView(Context context) {
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
return new CustomL16View(context);
}else{
return new CustomLegacyView(context);
}
}
}
Ответ 2
Общепринятой практикой является использование более новой цели сборки и гарантия того, что новый API будет вызван при правильных обстоятельствах. Google даже добавила аннотацию @TargetApi()
с ADT 17, чтобы указать локальные переопределения для условно загружаемого кода.
Подробнее см. Lint API check.
Ответ 3
1. У вас есть атрибуты Target Api
и Minimum SDK
, чтобы определить, какое устройство вы используете , и это будет наименьшая версия Api, на которой он будет работать.
2. Target Api
будет тем, на котором приложение работает с полными функциями, тогда как Minimum SDK
сделает приложение запущено на нем с помощью < некоторые компромиссы, так как могут быть шансы, что более низкая версия API не имеет функций, которые находятся в более высоких версиях.