android - 在自定义 lint 规则中解析资源值

标签 android lint android-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”。

有没有办法在处理 MyCustomComponent 元素时将“@dimen/standard_anim_factor”解析为资源的实际值(即“1.85”)?

最佳答案

值解析的一般问题是,它们取决于您所在的 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());
    }

注意:我还没有测试过上面的代码。所以请将其视为理论建议:-)

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

只是对您的自定义 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){
    ...
}

但这只是一个偏好问题:-)

关于android - 在自定义 lint 规则中解析资源值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30357155/

相关文章:

android - getFragmentManager() 返回 null

android - 找不到 lint-checks.jar

Android Studio 删除 lint 错误

android - 抑制 "Identifier not allowed in Android"

android - CursorAdapter 在 android 4 上运行缓慢

java - 删除 Android 列表中的最后一项

c - Lint 警告 506 : prio3: Constant value Boolean

php - 这如何成为有效的 php 语法

java - 如何在android中通过匹配字符串从查询中检索int id?