Разрешение значений ресурсов в пользовательском правиле lint
У меня есть большая база данных Android, и я пишу пользовательское правило lint, которое проверяет, попадают ли значения определенных атрибутов в заданный диапазон.
Например, у меня есть этот компонент:
<MyCustomComponent
my:animation_factor="0.7"
...>
</MyCustomComponent>
и я хочу написать правило lint, которое предупреждает разработчиков о том, что значения my:animation_factor
>= 1 следует использовать с осторожностью.
Я выполнил инструкции http://tools.android.com/tips/lint-custom-rules и смог получить значение my:animation_factor
с помощью этого кода:
import com.android.tools.lint.detector.api.*;
public class XmlInterpolatorFactorTooHighDetector {
....
@Override
public Collection<String> getApplicableElements() {
return ImmutableList.of("MyCustomComponent");
}
@Override
public void visitElement(XmlContext context, Element element) {
String factor = element.getAttribute("my:animation_factor");
...
if (value.startsWith("@dimen/")) {
// How do I resolve @dimen/xyz to 1.85?
} else {
String value = Float.parseFloat(factor);
}
}
}
Этот код отлично работает, когда атрибуты, такие как my:animation_factor
, имеют литеральные значения (например, 0.7
).
Однако, когда значением атрибута является ресурс (например, @dimen/standard_anim_factor
), тогда element.getAttribute(...)
возвращает строковое значение атрибута вместо фактического разрешенного значения.
Например, когда у меня есть MyCustomComponent
, который выглядит так:
<MyCustomComponent
my:animation_factor="@dimen/standard_anim_factory"
...>
</MyCustomComponent>
и @dimen/standard_anim_factor
определяется в другом месте:
<dimen name="standard_anim_factor">1.85</dimen>
тогда строка factor
станет "@dimen/standard_anim_factor" вместо "1.85".
Есть ли способ разрешить "@dimen/standard_anim_factor" фактическое значение ресурса (т.е. "1.85" ) при обработке элемента MyCustomComponent
?
Ответы
Ответ 1
Общая проблема с разрешением значений заключается в том, что они зависят от контекста среды выполнения Android, в котором вы находитесь. Может быть несколько папок values
с разными конкретными значениями для вашего ключа @dimen/standard_anim_factory
, поэтому просто вам известно из.
Тем не менее, AFAIK существует два варианта:
-
Выполните двухфазное обнаружение:
- Этап 1. Сканирование ваших ресурсов
- Сканируйте свой атрибут и поместите его в список (вместо того, чтобы немедленно его оценить)
- Сканируйте свои значения измерения и поместите их в список.
- Фаза 2:
- переопределить
Detector.afterProjectCheck
и разрешить ваши атрибуты, итерации по двум спискам, заполненным в фазе 1
-
обычно класс LintUtils
[1] является идеальным местом для этого материала, но, к сожалению, нет метода, который разрешает значения размеров. Однако существует метод под названием getStyleAttributes
, который демонстрирует, как разрешать значения ресурсов. Таким образом, вы можете написать свой собственный удобный метод для определения значений измерения:
private int resolveDimensionValue(String name, Context context){
LintClient client = context.getDriver().getClient();
LintProject project = context.getDriver().getProject();
AbstractResourceRepository resources = client.getProjectResources(project, true);
return Integer.valueOf(resources.getResourceItem(ResourceType.DIMEN, name).get(0).getResourceValue(false).getValue());
}
Примечание: Я еще не тестировал вышеуказанный код. Поэтому, пожалуйста, см. Теоретические советы: -)
Еще один небольшой совет для вашего пользовательского кода правила Lint, так как вас интересует только этот атрибут:
Вместо того, чтобы делать что-то подобное в visitElement
:
String factor = element.getAttribute("my:animation_factor");
... вы можете сделать что-то вроде этого:
@Override
public Collection<String> getApplicableAttributes() {
return ImmutableList.of("my:animation_factor");
}
@Override
void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute){
...
}
Но это просто вопрос предпочтения: -)
Ответ 2
Я считаю, что вы ищете getResources().getDimension()
.
Источник: http://developer.android.com/reference/android/content/res/Resources.html#getDimension%28int%29
Ответ 3
Предположив xml node после анализа ваших данных, попробуйте выполнить
Element element = null; //It is your root node.
NamedNodeMap attrib = (NamedNodeMap) element;
int numAttrs = attrib.getLength ();
for (int i = 0; i < numAttrs; i++) {
Attr attr = (Attr) attrib.item (i);
String attrName = attr.getNodeName ();
String attrValue = attr.getNodeValue ();
System.out.println ("Found attribute: " + attrName + " with value: " + attrValue);
}