Android Lint扫描规则说明(二)

主要内容

对Android Studio支持的六类Android Lint规则, 本文主要对Performance包含的32个项的说明,主要内容都是文档翻译,适当加一些本身的感想。html

分类详细说明

高效使用资源

UnusedIds

未被使用的资源id,在layout文件中定义了资源ID从未被使用过,但有时候它们可让layout更容易阅读,没有必要删除未使用的资源id。java

Overdraw

过分绘制:一个绘制区域被绘制的次数多于一次。android

若是给一个root view设置了背景图,就要给它设置一个background=nulltheme,不然绘制过程会先绘制themebackground,而后再绘制设置的背景图,彻底覆盖以前绘制的theme.background,这是 过分绘制算法

这个检测器依赖于根据扫描Java代码找出哪些布局文件与哪些Activity相关联,目前它使用的是一种不精确的模式匹配算法。所以,可能会因错误地推断布局与活动的关联而给出错误的提醒。app

若是想把一个背景图应用在多个页面上,能够考虑自定义theme,并把背景图设置在theme里,在layout中设置theme代替设置background。若是背景图中有透明的部分,而且但愿他和theme的背景有层叠效果,那么能够选择先把两个背景合并成一个背景图以后,在定义到theme里。less

VectorPath

关于SVG的使用,给出一篇参考文章:Android vector标签 PathData 画图超详解,Android Studio能够建立使用SVG绘制出的drawable图像资源。ide

UselessLeaf

没有包含任何View,也没有设置背景的Layout是多余的,能够去掉。让界面更趋于扁平,嵌套更高效。函数

UselessParent

若是一个包含ViewLayout没有兄弟层级的Layout,而他的外部ViewGroup又不是ScrollView或者root级别,那么这个Layout能够移除,让他包含的View直接包含在它的父层级的Layout中。让界面更趋于扁平,嵌套更高效。oop

TooDeepLayout

Layout嵌套过深会影响性能,考虑使用平铺类型的Layout代替。默认最深的View嵌套是10层,也能够经过环境变量ANDROID_LINT_MAX_DEPTH进行设置。System.getenv("ANDROID_LINT_MAX_DEPTH");语句获取,如何设置还没找到。布局

TooManyViews

Layout内有太多的View:一个Layout文件内有过多的View会影响性能。考虑使用复合drawables或其余技巧来减小这个布局中的视图数量。默认最多的数量是80个,能够经过环境变量ANDROID_LINT_MAX_VIEW_COUNT进行设置。听说这个变量能够用System.getenv("ANDROID_LINT_MAX_DEPTH");语句获取,如何设置还没找到。

NestedWeights

Weight嵌套:使用非0layout-weight值,须要Layout被测量两次,若是一个包含非0值的LinearLayout被嵌套在另外一个包含非0值的LinearLayout内部,那么,测量次数就会呈指数级增加。

DuplicateDivider

这个主要是讲RecyclerView的分割线,com.android.support:recyclerview-v7 提供了一个类DividerItemDecoration设置分割线样式,这个类在早期的版本内没有包含,因此在更新为新的版本后,可使用这个类从新设置分割线。 具体使用,参考文章:Android RecyclerView 使用彻底解析

MergeRootFrame

FrameLayout在一个layout文件中是root且没有使用background或者padding等属性,一般使用一个merge标签代替FrameLayout会更高效。可是这要看上下文设置,因此在替换以前要确认你已经理解了merge标签的工做原理

UnusedResources

未使用的资源:多指的是drawable类型的资源。多余的drawable资源会让APP变大,编译过程变长。

InefficientWeight

当LinearLayout只有一个Widget且使用了android:layout_weight时,定义对应的width/height的值为0dp,Widget就会自动占满剩余空间。由于不须要预先计算本身的尺寸,这种方式更高效。

高效的设置

DisableBaselineAlignment

在使用LinearLayout实现空间的按比例分割时,LinearLayout的空间用layout_weight属性在所包含的几个layout中间分割,那么应该设置被分割LinearLayoutbaseLineAligned="false",这样能够加快分割空间所作的运算。

LogConditional

LogConditional:使用android.util.Log打印调试日志,通常只会在DEBUG模式下使用,在release是不须要打印调试日志的,在buildToolsVersion大于等于17时, BuildConfig提供两个一个DEBUG常量来标记是否处于DEBUG模式,咱们能够用if(BuildConfig.DEBUG){}包裹调试日志语句,这样编译器会在编译生成release包时,删除这些语句。若是真的须要在release模式下打印调试日志,可使用@SuppressLint("LogConditional")注解告诉编译器在release包中保留这些日志信息。

UnpackedNativeCode

APP使用System.loadLibrary()加载Native库时,android 6.0或者更新的版本能够在Manifest文件中application标签中添加属性android:extractNativeLibs="false",这样能够提交加载速度,下降APP占用的存储空间。

更高效的替代方案

FloatMath

不要使用FloatMath类进行数学计算,推荐使用Math类。

Android早期版本由于浮点运算性能的缘由,推荐使用FloatMath代替Math类进行数学计算。随着硬件和系统的发展,这个问题已经不复存在,甚至通过JIT优化以后的Math类运算速度会比FloatMath更快,因此,在Android F以上版本的系统上,能够直接使用Math类,而不是FloatMath。

UseValueOf

某些类构造新对象时,建议使用工厂方法,而不是new关键字声明新的对象。例如,new Intger(0)就可使用Integer.valueOf(0)替代,工厂方法会使用更少的内存,由于它会让值相等的对象使用同一个实例。

ViewHolder

在给ListViewGradView之类的列表实现Adapter时,不能每次getView调用都去inflate一个新的layout,若是接口参数中给出了一个能够复用的View对象,就可使用这个对象而不是从新生成。这个应该都很熟悉,也很简单基础了。

UseSparseArrays

KeyInteger类型的HashMap可使用SparseArray代替,性能更好。可使用替代HashMap的有SparseBooleanArray、SparseIntArray、SparseLongArray和泛型类SparseArray,每一个对应的类型表明Value的类型。若是在某些状况必定要用HashMap实现,则能够用@SuppressLint注解抑制Lint检查。

WakelockTimeout

关于week lock的使用,这里提供一篇博客文章:Android 功耗分析之wakelock

UseCompoundDrawables

在一个TextView的四周有只具备展现做用的ImageView时,建议删除ImageView改用compound drawables:drawableTop, drawableLeft, drawableRight,drawableBottom,drawablePadding替代方案实现。

有关泄漏的提醒

Recycle

缺乏recycle()调用:许多资源例如:TypedArrays, VelocityTrackers在使用完以后须要调用recycle()方法回收资源。

ViewTag

4.0版本系统以前,View.setTag(int, Object)的实现方式中,会把Object存储在一个静态的map里而且使用的是强引用。这就意味着若是这个Object包含了对Context对象的引用,这个Context就是泄漏了。

传递一个View作参数,这个View就能提供一个对建立它的Context的引用。相似的,View holders内包含View,也会有Context与这个View相关联。

HandlerLeak

Handler引用泄漏:声明Handler的子类如MyHandler为内部类,若是MyHandler类对象关联Looper.getMainLooper()或者Looper.getMainLooper().getQueue()时,会阻止无用的外部类对象被垃圾回收,致使泄漏。若是对应main thread 的关联,就不会有这个问题。

应对方法,声明MyHandler为静态内部类,并用WeakReference的方式持有一个外部类对象,MyHandler使用这个对象操做外部类的属性和方法。

DrawAllocation

绘制过程当中的内存分配:避免在布局绘制过程当中分配内存给新的对象。由于这些操做调用频率比较高,频繁分配内存会唤起垃圾回收,中断UI绘制,致使卡顿。

StaticFieldLeak

非静态内部类具备对其外部类对象的隐式引用。

若是外部类Fragment或者Activity,那么这个引用意味着长时间运行的处理程序/加载器/任务(handler/loader/task)将持外部类对象的引用,从而防止外部类对象被回收。

同理,长时间运行的处理程序/加载器/任务(handler/loader/task)对Fragment或者Activity的直接引用,也会形成泄漏。

ViewModel类应该禁止引用View或者non-application类型的Context对象。

代码提醒

AnimatorKeep

属性动画默认支持的属性以下面列表。若是超出这些范围,会经过反射调用本地定义的函数。声明一个属性动画对象例如:ObjectAnimator.ofFloat(view, "rotation", 0, 360) 中的“rotation”就是要操做的属性,若是属性不在下面的列表中例如ObjectAnimator.ofFloat(view, "position", 0, 360),就须要本地定义一个对应的方法setPosition(float position),而且这个方法须要加上@keep注解,防止被当作无用方法清理掉。

static {
        PROXY_PROPERTIES.put("alpha", PreHoneycombCompat.ALPHA);
        PROXY_PROPERTIES.put("pivotX", PreHoneycombCompat.PIVOT_X);
        PROXY_PROPERTIES.put("pivotY", PreHoneycombCompat.PIVOT_Y);
        PROXY_PROPERTIES.put("translationX", PreHoneycombCompat.TRANSLATION_X);
        PROXY_PROPERTIES.put("translationY", PreHoneycombCompat.TRANSLATION_Y);
        PROXY_PROPERTIES.put("rotation", PreHoneycombCompat.ROTATION);
        PROXY_PROPERTIES.put("rotationX", PreHoneycombCompat.ROTATION_X);
        PROXY_PROPERTIES.put("rotationY", PreHoneycombCompat.ROTATION_Y);
        PROXY_PROPERTIES.put("scaleX", PreHoneycombCompat.SCALE_X);
        PROXY_PROPERTIES.put("scaleY", PreHoneycombCompat.SCALE_Y);
        PROXY_PROPERTIES.put("scrollX", PreHoneycombCompat.SCROLL_X);
        PROXY_PROPERTIES.put("scrollY", PreHoneycombCompat.SCROLL_Y);
        PROXY_PROPERTIES.put("x", PreHoneycombCompat.X);
        PROXY_PROPERTIES.put("y", PreHoneycombCompat.Y);
    }
复制代码
ObsoleteSdkInt

无用的SDK版本检查:Android SDK的版本更新比较快,许多API的使用都须要经过检查SDK版本防止出现not found之类的崩溃。在APP迭代的过程当中提高了minSdkVersion的值就会致使部分SDK版本检查再也不须要。

这种SDK版本检查会引发没必要要的资源搜索。

DevModeObsolete

之前,文档中建议在productFlavors中建立一个dev product。设定minSdkVersion 21,在开发过程当中激活multidexing加速构建过程。如今已经不须要这么作了,在新版的IDE和Gradle插件中,会自动地识别所链接设备的API level,若是连接的设备API level大于等于21,就会自动打开multindexing,就跟以前设置了dev product的效果同样。

参考:Enable Android MultiDex

ObsoleteLayoutParam

无用的LayoutParam:当给Widget使用了所在Layout没有提供的LayouParam时,会有这个提示。这种状况通常出如今修改Layout类型时没有同时修改内部Widget的LayoutParam设置或者把一个Widget从一个Layout拷贝到另外一个不一样类型的Layout内部。

这种无用的LayoutParam在运行时会引发无效的属性解析,也会误导阅读这些代码的人。因此应该把这些无用的属性删除掉。

其余

WearableBindListener
UseOfBundledGooglePlayServices
相关文章
相关标签/搜索