Resolución de valores de recursos en reglas personalizadas de pelusa

Tengo una base de código Android grande y estoy escribiendo una regla de pelusa personalizada que comprueba si los valores de ciertos atributos se encuentran dentro de un rango determinado.

Por ejemplo, tengo este componente:

<MyCustomComponent my:animation_factor="0.7" ...> </MyCustomComponent> 

Y quiero escribir una regla de pelusa que avisa a los desarrolladores que los valores de my:animation_factor > = 1 deben utilizarse con precaución.

Seguí las instrucciones en http://tools.android.com/tips/lint-custom-rules y logré recuperar el valor de my:animation_factor usando este código:

 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); } } } 

Este código funciona bien cuando atributos como my:animation_factor tienen valores literales (por ejemplo, 0.7 ).

Sin embargo, cuando el valor del atributo es un recurso (por ejemplo, @dimen/standard_anim_factor ) entonces element.getAttribute(...) devuelve el valor de cadena del atributo en lugar del valor resuelto real.

Por ejemplo, cuando tengo un MyCustomComponent que se parece a esto:

 <MyCustomComponent my:animation_factor="@dimen/standard_anim_factory" ...> </MyCustomComponent> 

Y @dimen/standard_anim_factor se define en otra parte:

 <dimen name="standard_anim_factor">1.85</dimen> 

Entonces el factor cadena se convierte en "@ dimen / standard_anim_factor" en lugar de "1.85".

¿Hay una manera de resolver "@ dimen / standard_anim_factor" al valor real del recurso (es decir, "1.85") mientras se procesa el elemento MyCustomComponent ?

El problema general con la resolución de valores es que dependen del contexto de ejecución de Android en el que se encuentre. Puede haber varias carpetas de values con diferentes valores concretos para su clave @dimen/standard_anim_factory , de modo que usted sepa.

Sin embargo, AFAIK existen dos opciones:

  • Realice una detección de dos fases:

    • Fase 1: Escanee sus recursos
    • Busca tu atributo y ponlo en una lista (en lugar de evaluarlo inmediatamente)
    • Analiza tus valores de dimensión y ponlos en una lista también
    • Fase 2:
    • Anule Detector.afterProjectCheck y resuelva sus atributos iterando sobre las dos listas llenadas dentro de la fase 1
  • Por lo general la clase LintUtils [1] es un lugar perfecto para ese material, pero por desgracia no hay ningún método que resuelve los valores de las dimensiones. Sin embargo, hay un método llamado getStyleAttributes que demuestra cómo resolver valores de recursos. Así que usted podría escribir su propio método conveniente para resolver valores de dimensión:

 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()); } 

Nota: No he probado el código anterior todavía. Así que por favor verlo como un consejo teórico 🙂

  1. https://android.googlesource.com/platform/tools/base/+/master/lint/libs/lint-api/src/main/java/com/android/tools/lint/detector/api/LintUtils.java

Sólo un consejo más leve para su código de regla Lint personalizado, ya que sólo están interesados ​​en el atributo:

En lugar de hacer algo como esto en visitElement :

 String factor = element.getAttribute("my:animation_factor"); 

… puede que desee hacer algo como esto:

 @Override public Collection<String> getApplicableAttributes() { return ImmutableList.of("my:animation_factor"); } @Override void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute){ ... } 

Pero es sólo una cuestión de preferencia 🙂

Creo que estás buscando buscar getResources().getDimension() .

Fuente: http://developer.android.com/reference/android/content/res/Resources.html#getDimension%28int%29

Asumiendo que el nodo xml después de analizar sus datos, intente lo siguiente

 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); } 
  • Manera correcta de manejar la advertencia de pelusa de NullPointerException de Android Studio
  • Guardando cualquier archivo en eclipse me da el siguiente error:
  • Retrolambda: Lint se bloquea al usar expresiones lambda con retrolambda
  • ¿hay alguna manera de configurar gradle para comprobar la ortografía en strings.xml?
  • Creación de un detector Lint Java personalizado
  • ¿Por qué estoy recibiendo una advertencia sin marcar?
  • Limpieza de los permisos de Android no utilizados
  • SignedConfigs me da un error de Lint en build.gradle después de actualizar a v22
  • La regla de la lechada personalizada no aparece en el estudio de eclipse / android
  • Sonar Android Lint sin problemas encontrados
  • El soporte de diseño de derecha a izquierda está causando problemas de advertencia en el editor de xml
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.