В этой статье я хотел бы представить несколько проблем, с которыми я столкнулся при разработке приложений для Android, и способы их решения.
Статический контекст Проблема: Я хотел бы иметь возможность вызывать некоторые методы контекста из статического контекста (простите за каламбур).
Решение: Я использовал решение с переполнение стека , который состоит из создания статического класса приложения.
Здесь нужно быть осторожным – и использовать его с умом.
Например, для получения ресурсов – переводов, картинок, стилей.
Где его нельзя использовать: для работы с элементами GUI или, например, с LayoutInflator (будет выдано исключение).
На практике это будет выглядеть так:
И AndroidManifest.xml:public class ApplicationContext extends android.app.Application { @NotNull private static ApplicationContext instance; public ApplicationContext() { instance = this; } @NotNull public static ApplicationContext getInstance() { return instance; } }
<manifest xmlns:a="http://schemas.android.com/apk/res/android ">
<application a:name=".
ApplicationContext">
// .
</application>
</manifest>
Использование API Android более высокого уровня в приложении более низкого уровня Проблема: Я хочу использовать функции, доступные в API более высокого уровня (например, элементы графического интерфейса — представления).
Решение: Android — открытая платформа, поэтому исходники доступны.
Давайте возьмем и перенесем недоступные классы в нашу библиотеку.
Естественно, у такого подхода есть и минусы: нужно проверять работоспособность переданных классов и редактировать зависимости, которые не поддерживаются на этом уровне API (тут как повезет).
Пример: НомерПиккер Доступен только с 11 уровня, но я перенес его в свой проект и использую с 4 уровнем: посмотри на гитхабе Использование XML API Проблема: Часто бывает необходимо преобразовать объект Java в представление XML (например, для передачи объекта между сервисами или для сохранения его в состоянии персистентности).
Обычно в таких случаях используется JAXB, но на платформе Android JAXB недоступен.
Решение: используя другую библиотеку.
Например, я использовал Simple (сериализация XML).
simple.sourceforge.net Как использовать?
Для начала подключим библиотеку к проекту: <dependency>
<groupId>org.simpleframework</groupId>
<artifactId>simple-xml</artifactId>
<version>2.6.1</version>
<exclusions>
<exclusion>
<artifactId>stax-api</artifactId>
<groupId>stax</groupId>
</exclusion>
</exclusions>
</dependency>
Обратите внимание: для stax-api установлено исключение — иначе проект не соберётся (Android api не поддерживается)
Отмечаем объекты необходимыми аннотациями (@Root, Переходный процесс , Элемент ):
@Root
public class Var implements IConstant {
@Transient
private Integer id;
@Element
@NotNull
private String name;
@Element(required = false)
@Nullable
private String value;
//.
private Var() {
}
}
Сохраняем объект в xml:
final StringWriter sw = new StringWriter();
final Serializer serializer = new Persister();
try {
serializer.write(vars, sw);
} catch (Exception e) {
throw new RuntimeException(e);
}
Получаем объект из xml:
final String value = getVarString();
final Serializer serializer = new Persister();
try {
final Vars vars = serializer.read(Vars.class, value);
// .
} catch (Exception e) {
throw new RuntimeException(e);
}
Хранение переводов (избегая зависимости от класса R) Проблема: В Android есть механизм получения переводов по идентификатору поля класса R, и где бы вы ни захотели использовать данный перевод, у вас должна быть зависимость от этого класса.
Решение: кэш переводов на уровне приложения, в котором хранятся переводы по имени и языку.
Перевод взят из статического контекста.
Пример кода:
public enum TranslationsCache {
instance;
// first map: key: language id, value: map of captions and translations
// second mal: key: caption id, value: translation
private final Map<String, Map<String, String>> captions = new HashMap<String, Map<String, String>>();
private Class<?> resourceClass;
private Context context;
/**
* Method load captions for default locale using android R class
* @param context STATIC CONTEXT
* @param resourceClass class of captions in android (SUBCLASS of R class)
*/
public void initCaptions(@NotNull Context context, @NotNull Class<?> resourceClass) {
initCaptions(context, resourceClass, Locale.getDefault());
}
/**
* Method load captions for specified locale using android R class
* @param context STATIC CONTEXT
* @param resourceClass class of captions in android (SUBCLASS of R class)
* @param locale language to be used for translation
*/
public void initCaptions(@NotNull Context context, @NotNull Class<?> resourceClass, @NotNull Locale locale) {
assert this.resourceClass == null || this.resourceClass.equals(resourceClass);
this.context = context;
this.resourceClass = resourceClass;
if (!initialized(locale)) {
final Map<String, String> captionsByLanguage = new HashMap<String, String>();
for (Field field : resourceClass.getDeclaredFields()) {
int modifiers = field.getModifiers();
if (Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers)) {
try {
int captionId = field.getInt(resourceClass);
captionsByLanguage.put(field.getName(), context.getString(captionId));
} catch (IllegalAccessException e) {
Log.e(ResourceCache.class.getName(), e.getMessage());
}
}
}
captions.put(locale.getLanguage(), captionsByLanguage);
}
}
private boolean initialized(@NotNull Locale locale) {
return captions.containsKey(locale.getLanguage());
}
/**
* @param captionId id of caption to be translated
* @return translation by caption id in default language, null if no translation in default language present
*/
@Nullable
public String getCaption(@NotNull String captionId) {
return getCaption(captionId, Locale.getDefault());
}
/**
* @param captionId id of caption to be translated
* @param locale language to be used for translation
* @return translation by caption id in specified language, null if no translation in specified language present
*/
@Nullable
public String getCaption(@NotNull String captionId, @NotNull final Locale locale) {
Map<String, String> captionsByLanguage = captions.get(locale.getLanguage());
if (captionsByLanguage != null) {
return captionsByLanguage.get(captionId);
} else {
assert resourceClass != null && context != null;
initCaptions(context, resourceClass, locale);
captionsByLanguage = captions.get(locale.getLanguage());
if (captionsByLanguage != null) {
return captionsByLanguage.get(captionId);
}
}
return null;
}
}
Затем вы можете использовать его, например, так:
try{
//.
} catch ( SomeException e ) {
TranslationsCache.instance.getCaption(e.getMesageId());
}
Заключение
Все описанное выше было реализовано на практике:
Исходный код доступен по адресу github.com .
Рабочее приложение на Android Market .
Спасибо за внимание! Теги: #Android #разработка #Android #разработка #xml #java #java #ммм кофе #Разработка Android
-
Как Отслеживать Настроения В Твиттере
19 Oct, 24 -
В Git Или Не В Git
19 Oct, 24 -
Что Происходит С Зеленой Энергетикой
19 Oct, 24 -
Классика Живописи И Ценообразование Проектов
19 Oct, 24 -
Стальной Корпус Kublai Kl02 От Silverstone
19 Oct, 24