Android应用优化(2)View cache的优化

在Android的显示机制中,View的软件渲染都是基于bitmap图片进行的处理。并且刷新机制中只要是与脏数据区有交集的视图都将重绘,所以在View的设计中就有一个cache的概念存在,这个cache无疑就是一个bitmap对象,它的存在本来是用来提高view绘制效率的,但是往往在应用的设计中也是一个影响性能的因素。

先看看关于cache概念的一些API吧,从中我们可以得到一些有效信息。
View:
    setDrawingCacheQuality(int)
Defines the quality of translucent drawing caches.
这个网上已经有博客进行了说明http://blog.csdn.net/xuxiake2012/article/details/5756302,可以采用一定的办法来使用RGB565格式,比默认的使用ARGB8888格式要节省内存和相应的处理时间从而优化View的绘制。
setDrawingCacheBackgroundColor(int color)
Setting a solid background color for the drawing cache's bitmaps will improve performance and memory usage.
setDrawingCacheEnabled(boolean enabled)
Enables or disables the drawing cache.这个就是是否保留缓存的开关了。
再看看ViewGroup里面还有几个:
setPersistentDrawingCache(int drawingCacheToKeep)
Indicates what types of drawing caches should be kept in memory after they have been created.
none                    0x0    The drawing cache is not persisted after use.
animation     0x1     The drawing cache is persisted after a layout animation.
scrolling                   0x2    The drawing cache is persisted after a scroll.
all                   0x3    The drawing cache is always persisted.

public void setAnimationCacheEnabled (boolean enabled)
Added in API level 1
Enables or disables the children's drawing cache during a layout animation. By default, the drawing cache is enabled but this will prevent nested layout animations from working. To nest animations, you must disable the cache.
好了,本文要说的关键点出来了,就是最后这一句如果需要使用layout animation就必须要禁用cache。下面开始分析
首先我们从ViewGroup禁用推出view的禁用。看源码

public void setAnimationCacheEnabled(boolean enabled) {
        setBooleanFlag(FLAG_ANIMATION_CACHE, enabled);
}

其实就是设置了一个标志。真正起作用当然是在Draw或者dispatchDraw的过程啦。
protected void dispatchDraw(Canvas canvas) {
        final int count = mChildrenCount;
        final View[] children = mChildren;
        int flags = mGroupFlags;

        if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {
            final boolean cache = (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;

            final boolean buildCache = !isHardwareAccelerated();
            for (int i = 0; i < count; i++) {
                final View child = children[i];
                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
                    final LayoutParams params = child.getLayoutParams();
                    attachLayoutAnimationParameters(child, params, i, count);
                    bindLayoutAnimation(child);
                    if (cache) {
                        child.setDrawingCacheEnabled(true);
                        if (buildCache) {                        
                            child.buildDrawingCache(true);
                        }
                    }
                }
            }
if (cache) {
                mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;
            }
……………

……………
}


后面的代码显示其实这个标志就是将child的draw cache进行了设置。这么看来做出的优化就是对View的cache做了控制,setPersistentDrawingCache中的几种参数其实也就是在控制这个东西,是在什么时候可用,比如animation设置后就是在动画前不可用,动画结束后可用并保存此时的cache。All设置就是一直保存cache。
接下来的重点就是分析一下,view里面的这个draw cache是如何在正常情况下优化绘制速度又是为什么会在animation时有阻碍的。看看view中的Draw方法。
boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
boolean caching;
……………
final int flags = parent.mGroupFlags;
…………..
    if ((flags & ViewGroup.FLAG_CHILDREN_DRAWN_WITH_CACHE) != 0 ||
                (flags & ViewGroup.FLAG_ALWAYS_DRAWN_WITH_CACHE) != 0) {
            caching = true;
            // Auto-scaled apps are not hw-accelerated, no need to set scaling flag on DisplayList
            if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired;
        } else {
            caching = (layerType != LAYER_TYPE_NONE) || hardwareAccelerated;
        }
    …………..
if (caching) {
            if (!hardwareAccelerated) {
                if (layerType != LAYER_TYPE_NONE) {
                    layerType = LAYER_TYPE_SOFTWARE;
                    buildDrawingCache(true);
                }
                cache = getDrawingCache(true);
            } else {
                switch (layerType) {
                    case LAYER_TYPE_SOFTWARE:
                        if (useDisplayListProperties) {
                            hasDisplayList = canHaveDisplayList();
                        } else {
                            buildDrawingCache(true);
                            cache = getDrawingCache(true);
                        }
                        break;
                    case LAYER_TYPE_HARDWARE:
                        if (useDisplayListProperties) {
                            hasDisplayList = canHaveDisplayList();
                        }
                        break;
                    case LAYER_TYPE_NONE:
                        // Delay getting the display list until animation-driven alpha values are
                        // set up and possibly passed on to the view
                        hasDisplayList = canHaveDisplayList();
                        break;
                }
            }
        }
     …………………..
     
}


这里说得很明显了,如果不禁止就在每次画子view时都要更新缓存并且将缓存画到画布中。这无疑是多了一步,画一个bitmap,animation需要不停的画所以也就多了很多操作,但是这个缓存不是说是对绘制视图的优化嘛,这个秘密就在view的invalidate中,当子view需要invalidate时事实上也是交个父布局在弄的。Invalidate有四个不同参数的方法,秘密在这个参数中。
void invalidate(boolean invalidateCache) {
     * @param invalidateCache Whether the drawing cache for this view should be invalidated as
     * well. This is usually true for a full invalidate, but may be set to false if the
     * View's contents or dimensions have not changed.
}


后面的代码代码就不一一列举了,那个不是本文分析的重点,重点是这个注释的意思,参数说是否需要更新缓存,也就是说如果没变动就不需要更新,也就可以直接将缓存画到画布上,这难道不是一种优化嘛。

好了,我们总结几个结论。首先,默认情况下采用软件渲染不需要对cache做特殊处理,然后,在确定自己的layout和view将使用animation时需要将drawcache禁止,需要设置AnimationCache为disable。最后就是我们需要主动重绘view时尽量调用带有参数的invalidate方法,这样可以减少很多操作优化性能,比如以上的invalidateCache参数,还有无效区域的参数等。

上面有些内容是我自己的理解,如有错误请大家一定要指出来,避免我一直理解错误。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值