`

Android中View绘制优化之三---- 优化View

 
阅读更多


 

本文原创, 转载请注明出处http://blog.csdn.net/qinjuning

 

 




译三:

优化视图




关于如何设计自定义View以及响应触摸时间等,请看Androiddeveloper :

 

地址:http://developer.android.com/training/custom-views/index.html

 

本文翻译地址:Optimizing the View



通过前面的学习,现在该设计良好的View能够响应手势以及状态之间进行转换,除此之外你必须确保View

运行的流畅快速。为了避免迟缓的UI效果或者运行的停顿,必须确保你的动画一直运行在每秒60帧。



越少越好


为了加速视图,从那些调用频繁的活动中减少不必要的代码。在OnDraw()方法中开始绘制,它会给你最大的

 

效益。特别低,你也应该减少在onDraw()方法中的内存分配,因为任何内存分配都可能导致内存回收,这将会

引起不连贯。 在初始化或者动画之间分配对象。绝不要在动画运行时分配内存。


另一方面需要减少onDraw()方法中的开销,只在需要时才调用onDraw()方法。通常invalidate()方法会调用

onDraw()方法,因此减少对invalidate()的不必要调用。如果可能,调用它的重载版本即带有参数的invalidate()

方法而不是无参的invalidate()方法。该带参数的方法invalidate()能使draw过程更有效,以及减少对落在该矩形

区域(参数指定的区域)外视图的不必要重绘 。


注,invalidate()的三个重载版本为:

1 、public voidinvalidate(Rectdirty)
2、public voidinvalidate(int l, int t, int r, int b)

3、public voidinvalidate()


另外的一个高代价的操作是布局过程(layout)。 任何时刻对View调用requestLayout()方法,Android UI 框架

都需要遍历整个View树,确定每个视图它们所占用的大小。如果在measure过程中有任何冲突,可能会多次遍历

View树。UI设计人员有时为了实现某些效果,创建了较深层次的ViewGroup。但这些深层次View树会引发效率

问题。确保你的View树层次尽可能浅。


如果你有的UI设计是复杂地,你应该考虑设计一个自定义ViewGroup来实现layout过程。不同于内置View控件,

自定义View能够假定它的每个子View的大小以及形状,同时能够避免为每个子View进行measure过程。 PieChart

展示了如何继承ViewGroup类。 PieChart带有子View,但它从来没有measure它们。相反,它根据自己的布局算法

去直接设置每个子View的大小。

如下代码所示:

 

/**
 * Custom view that shows a pie chart and, optionally, a label.
 */
public class PieChart extends ViewGroup {
    ...
    //
    // Measurement functions. This example uses a simple heuristic: it assumes that
    // the pie chart should be at least as wide as its label.
    //
    @Override
    protected int getSuggestedMinimumWidth() {
        return (int) mTextWidth * 2;
    }
    @Override
    protected int getSuggestedMinimumHeight() {
        return (int) mTextWidth;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // Try for a width based on our minimum
        int minw = getPaddingLeft() + getPaddingRight() + getSuggestedMinimumWidth();

        int w = Math.max(minw, MeasureSpec.getSize(widthMeasureSpec));

        // Whatever the width ends up being, ask for a height that would let the pie
        // get as big as it can
        int minh = (w - (int) mTextWidth) + getPaddingBottom() + getPaddingTop();
        int h = Math.min(MeasureSpec.getSize(heightMeasureSpec), minh);

        setMeasuredDimension(w, h);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        // Do nothing. Do not call the superclass method--that would start a layout pass
        // on this view's children. PieChart lays out its children in onSizeChanged().
    }
    
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        //
        // Set dimensions for text, pie chart, etc
        //
        // Account for padding

        ...

        // Lay out the child view that actually draws the pie.
        mPieView.layout((int) mPieBounds.left,
                (int) mPieBounds.top,
                (int) mPieBounds.right,
                (int) mPieBounds.bottom);
        mPieView.setPivot(mPieBounds.width() / 2, mPieBounds.height() / 2);

        mPointerView.layout(0, 0, w, h);
        onDataChanged();
    }

}


 

 

使用硬件加速


Android 3.0版本后,Android 2D图形库能在大多数Android设备上使用GPU(图形处理单元)加速。GPU硬件

 

加速可以极大的优化多数应用程序,但它并不是每个应用程序的最优选择。Android框架给予你是否在应用程序中

使用硬件加速的控制力。


<<如何运用硬件加速>>篇展示了如何在Application、Activity、Window级别中使用硬件加速。值得注意的是

我们必须手动在配置文件中设置应用程序API级别为11或者更高级别,即在 AndroidManifest.xml进行如下配置:
<uses-sdk android:targetSdkVersion="11"/>


一旦你开启了硬件加速,你可能看不到效率的提升。Mobile GPUs 善于处理特定的任务,例如:伸缩、旋转、

平移图片。它也有一些不擅长处理的任务,例如:绘制直线或曲线。常言道物尽其用,扬长避短,尽可能让GPU

处理它擅长的任务,减少让其处理弱势任务的。


在PieChart 示例中,例如,相对来说绘制一个圆形是比较耗费资源的。每次旋转引起的重绘导致UI的迟缓。

解决办法就是让View来呈现该圆形,并且设置该View的layer type属性为 LAYER_TYPE_HARDWARE,因此GPU

能够缓存静态图片。示例中该View作为 PieChart类的内部类存在,减少了为了实现这个方法的代码开销。

private class PieView extends View {

    public PieView(Context context) {
        super(context);
        if (!isInEditMode()) {
            setLayerType(View.LAYER_TYPE_HARDWARE, null);
        }
    }
    
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        for (Item it : mData) {
            mPiePaint.setShader(it.mShader);
            canvas.drawArc(mBounds,
                    360 - it.mEndAngle,
                    it.mEndAngle - it.mStartAngle,
                    true, mPiePaint);
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        mBounds = new RectF(0, 0, w, h);
    }

    RectF mBounds;
}



改变之后,只有View第一次显示的时候才会调用PieChart.PieView.onDraw()方法。在应用程序的其他

 

时间,绘制的图像将会作为图片缓存,重绘时GPU将任意旋转图像。


然而这只是一个折中手段。缓存图片作为硬件层导致 video memory开销,video memory却是一种受限制的

资源。 出于这个原因,在PieChart.PieView的最终版本上,只有在用户滑动时才设置它的layer type属性为

LAYER_TYPE_HARDWARE。在其他时间,仅仅设置它的layer type属性为 LAYER_TYPE_HARDWARE,这

允许GPU停止缓存图片。



最后,不要忘记分析你的代码。在一个View上做的优化技术可能会在其他View上产生不好的影响。

 


 

 

分享到:
评论

相关推荐

    Android中View绘制流程

    这些方法在Activity的`onCreate()`之后被调用,当需要更新界面时,系统会重新测量、布局和绘制View。 1. **onMeasure()**:此方法用于确定View的大小。每个View都会调用该方法来测量自身的宽高,通常会根据其父View...

    android自定义view之---组合view

    在Android开发中,自定义View是一项重要的技能,它允许开发者根据特定需求创建独特且功能丰富的用户界面组件。本文将深入探讨如何在Android中实现自定义组合View,即结合多个基本View来构建复杂视图。 首先,理解...

    Android自定义View之组合控件 ---- LED数字时钟

    在Android开发中,自定义View是一项重要的技能,它允许开发者创造出独特且富有创新性的用户界面。本主题将深入探讨如何创建一个LED数字时钟的自定义View,这是一款结合了多个基本控件并以LED风格显示时间的组件。LED...

    Android带未读提示的view-购物车-待收货-消息提示

    综上所述,实现“Android带未读提示的view-购物车-待收货-消息提示”涉及到了Android自定义视图的绘制、网络请求、数据监听、数据库操作以及用户体验优化等多个知识点。开发者需要具备扎实的Android基础,理解各种...

    Android代码-原创自定义控件之-Canvas实时绘制音乐波形图

    "Android代码-原创自定义控件之-Canvas实时绘制音乐波形图"这个项目旨在创建一个能够实时展示音乐波形的自定义View,通过Canvas进行图形绘制。尽管项目已废弃,但其中涉及的知识点仍对Android开发者具有参考价值。 ...

    Android应用源码之android-gif-drawable 支持fig显示的view-IT计算机-毕业设计.zip

    这个"Android应用源码之android-gif-drawable 支持fig显示的view"是一个针对这一需求的示例项目,适用于毕业设计学习。通过分析这个源码,我们可以深入了解如何在Android应用中有效地展示和控制GIF动图。 首先,`...

    Android-TrapezoidPartsView-梯形控件

    "the Trapezoid Parts View"是这个项目的核心类,它继承自Android的基础视图类`View`或`ViewGroup`,根据描述中的"draw Trapezoid image"推断,可能是直接继承自`View`,因为通常自定义绘图操作是在`View`中完成的。...

    Android ---------高德卫星地图绘制多个点和点的点击事件自定义弹窗

    在Android开发中,有时我们需要在地图上展示多个位置信息,比如交通路线、兴趣点分布等。高德地图API提供了一套完整的解决方案,使得开发者能够轻松地在卫星地图上绘制多个点,并实现点的点击事件来展示自定义弹窗。...

    Android应用源码之android-gif-drawable 支持fig显示的view.zip

    在Android开发中,有时我们需要在应用中展示动态GIF图像,这时就涉及到对GIF格式的支持。`android-gif-drawable`是一个流行的开源库,专门用于在Android应用中渲染和播放GIF图像。这个库提供了高效且灵活的方式来...

    Android利用View绘制饼状图,折线图,柱状图等

    总结来说,Android利用自定义View绘制饼状图、柱状图和折线图主要涉及到以下几个步骤: 1. 创建自定义View类。 2. 在`onMeasure()`方法中确定View的大小。 3. 在`onDraw()`方法中,根据数据计算图形的各个参数,如...

    Android中View(视图)绘制不同状态背景图片

    Android中View(视图)绘制不同状态背景图片原理深入分析Android中View(视图)绘制不同状态背景图片原理深入分析Android中View(视图)绘制不同状态背景图片原理深入分析Android中View(视图)绘制不同状态背景图片原理深入...

    Android 自定义View绘制居中文本

    在Android开发中,自定义View是一项常见的需求,它允许开发者根据特定的设计要求或者功能扩展来创建独特的用户界面组件。本文将深入探讨如何实现一个自定义的View,使其能够精确地绘制水平和垂直居中的文本,效果...

    Android自定义View实战---圆盘温度计(1)

    综上所述,创建Android自定义View——圆盘温度计,不仅涉及到图形绘制、事件处理,还涵盖了数据绑定、动画效果、性能优化等多个方面。通过这个实战项目,开发者可以深入理解Android视图系统的底层机制,提升自己的...

    Android中View绘制流程以及invalidate()等相关方法分析

    Draw阶段是实际的绘图操作,`onDraw()`方法在这里执行,开发者通常在此绘制View的内容。Post-Draw阶段包括了诸如动画、阴影等额外的渲染操作。 接下来,我们重点关注`invalidate()`方法。它是View更新的重要触发器...

    Android三角形的绘制

    在这个工程中,我们将创建三个Java类:OpenGL_Lesson2、OpenGlView和OpenGlRender。 OpenGL_Lesson2.java是我们的主Activity类,负责管理整个应用程序的生命周期。在这个类中,我们创建了一个OpenGlView对象,并将...

    Android-Android自定义View之几何图形绘制

    我们需要重写`onDraw()`方法,这是Android系统绘制View时调用的关键方法。 在`onDraw()`方法中,我们使用Canvas对象进行绘图。Canvas提供了各种绘图操作,如画线、画圆、画矩形以及复杂的路径绘制。例如,要绘制一...

    Android-自定义View绘制一个太极旋转图片demo

    综上所述,这个"Android-自定义View绘制一个太极旋转图片demo"涵盖了Android开发中的自定义视图绘制、动画效果以及资源管理等多个核心知识点。通过实践这个项目,开发者不仅可以提升Android图形绘制的能力,还能掌握...

    Android 自定义View实现水平温度计

    - 需要重写`onDraw()`方法,这是绘制View的主要入口,所有图形绘制都在这里进行。 2. **图形绘制**: - 使用`Canvas`对象进行绘图,如画线、矩形、圆形等。在`onDraw()`方法中,我们需要使用`canvas.drawLine()`...

Global site tag (gtag.js) - Google Analytics