Android自定义View

自定义view绘制优化

2019-02-20  本文已影响32人  天平GG
<一>降低刷新频率

为了提高view的运行速度,减少来自于频繁调用的程序的不必要的代码。从onDraw()方法开始调用,这会给你带来最好的回报。特别地,在onDraw()方法中你应该减少冗余代码,冗余代码会带来使你view不连贯的垃圾回收。初始化的冗余对象,或者动画之间的,在动画运行时,永远都不会有所贡献。

加之为了使onDraw()方法更有依赖性,你应该尽可能的不要频繁的调用它。大部分时候调用 onDraw()方法就是调用invalidate()的结果,所以减少不必要的调用invalidate()方法。有可能的,调用四种参数不同类型的invalidate(),而不是调用无参的版本。无参变量需要刷新整个view,而四种参数类型的变量只需刷新指定部分的view.这种高效的调用更加接近需求,也能减少落在矩形屏幕外的不必 要刷新的页面。

另外一个非常耗时的操作是请求layout。任何时候执行requestLayout(),会使得Android UI系统去遍历整个View的层级来计算出每一个view的大小。如果找到有冲突的值,它会需要重新计算好几次。另外需要尽量保持View的层级是扁平化的,这样对提高效率很有帮助。 如果你有一个复杂的UI,你应该写一个自定义的ViewGroup类来表现它的布局。不同于内置的 view类,你的自定义view能关于尺寸和它子控件的形状做出应用特定的假想,同时避免通过它子类来 计算尺寸。这圆图例子显示怎样作为自定义view一部分来继承ViewGroup类,圆图有它子view类, 但是重来都不测量他们。相反地,它直接地通过自己自定义的布局算法来设定他们的尺寸大小。

如果你有一个复杂的UI,你应该考虑写一个自定义的ViewGroup来执行他的layout操作。与内置的view不同,自定义的view可以使得程序仅仅测量这一部分,这避免了遍历整个view的层级结构来计算大小。这个PieChart 例子展示了如何继承ViewGroup作为自定义view的一部分。PieChart 有子views,但是它从来不测量它们。而是根据他自身的layout法则,直接设置它们的大小。

<二>使用硬件加速

作为Android3.0,Android2D图表系统可以通过大部分新的Android装置自带GPU(图表处理单元)来增加,对于许多应用程序 来说,GPU硬件加速度能带来巨大的性能增加,但是对于每一个应用来讲,并不都是正确的选择。Android框架层更好地为你提供了控制应用程序部分硬件 是否增加的能力。

怎样在你的应用,活动,或者窗体级别中使用加速度类,请查阅Android开发者指南中的Hardware Acceleration类。注意到在开发者指南中的附加说明,你必须在你的AndroidManifest.xml 文件中的<uses-sdk android:targetSdkVersion="11"/>中将应用目标API设置到11或者更高的级别。

一旦你使用硬件加速度类,你可能没有看到性能的增长,手机GPUs非常擅长某些任务,例如测量,翻转,和平移位图类的图片。特别地,他们不擅长其他的任务,例如画直线和曲线。为了利用GPU加速度类,你应该增加GPU擅长的操作数量,和减少GPU不擅长的操作数量。

在PieChart 例子中,例如,画一个饼图相对来说是比较麻烦的。每次重新画饼图,它的翻转都会给UI界面带来不流畅的感觉。解决方案就是在子View类中放置饼图和将View的布局类型设置为 LAYER_TYPE_HARDWARE,这样GPU能将它作为静态图片缓存。样例将子view作为PieChart的内部类来定义,这样减少了来自于需要实现方案的大量代码的改动。

<三>初始化时创建对象;不要在onDraw方法内创建绘制对象,一般都在构造函数里面初始化对象;
@Override
protected void onDraw(Canvas canvas) {
    if (getDrawable() == null) {
        return;
    }
    setUpShader();
    canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));
    if (mType == TYPE_ROUND) {
        canvas.drawRoundRect(mRoundRect, mBorderRadius, mBorderRadius, mBitmapPaint);
    } else {
        canvas.drawCircle(mRadius, mRadius, mRadius, mBitmapPaint);
    }
}
<四>状态的存储与恢复:如果内存不足,而恰好我们的Activity置于后台,不幸被重启,或者用户旋转屏幕造成Activity重启,我们的View应该也能尽可能的去保存自己的属性。
@Override
protected Parcelable onSaveInstanceState() {
    Bundle bundle = new Bundle();
    bundle.putParcelable(STATE_INSTANCE, super.onSaveInstanceState());
    bundle.putInt(STATE_TYPE, mType);
    bundle.putInt(STATE_BORDER_RADIUS, mBorderRadius);
    return bundle;
}

@Override
protected void onRestoreInstanceState(Parcelable state) {
    if (state instanceof Bundle) {
        Bundle bundle = (Bundle) state;
        super.onRestoreInstanceState(((Bundle) state).getParcelable(STATE_INSTANCE));
        this.mType = bundle.getInt(STATE_TYPE);
        this.mBorderRadius = bundle.getInt(STATE_BORDER_RADIUS);
    } else {
        super.onRestoreInstanceState(state);
    }
}
上一篇下一篇

猜你喜欢

热点阅读