关于Android的硬件加速和ViewPager

原文链接 l

ViewPager and Hardware acceleration


Romain Guy在上周上传了一篇关于硬件加速的博文 Optimizing hardware layers 他解释了硬件加速在一些方面是怎样提升动画的性能,但是在另外一些方面使用硬件加速可能会适得其反。

如果一个view被硬件层所支持,那么硬件层会随着view的更新而更新,之后硬件层上的内容会被绘制到屏幕上。有意思的是,如果你在你的动画过程中改变了view,对于动画的每一帧来说将会做更多的工作,进而会出现掉帧的情况。所以如果你在调用了硬件层之后又改变了view,这是非常不明智的。

在他的文章中他提出了一个简单的方案来检查这个问题,打开手机开发者选项中的“显示硬件层更新”。vIew会在硬件层更新的时候变成绿色。

所以我尝试了一下。

我测试了一个我正在编写的APP,我发现当我滑动ViewPager的时候会变成绿色。但是我并没有设置硬件层更新啊!所以我决定寻找出“真凶”。为了找到“真凶”,我使用了一个小技巧,在滑动ViewPager的时候,我在TraceView中对方法按照方法名进行了排序,并且搜索了“android/view/View.setLayerType"方法并且一直跟踪直到我找到了真正的原因,ViewPager#enableLayers();

private void enableLayers(boolean enable) {
    final int childCount = getChildCount();
    for (int i = 0; i < childCount; i++) {
        final int layerType = enable ?
                ViewCompat.LAYER_TYPE_HARDWARE : ViewCompat.LAYER_TYPE_NONE;
        ViewCompat.setLayerType(getChildAt(i), layerType, null);
    }
}

这是一个管理是否开启ViewPager子View的硬件层的方法。在ViewPager#setScrollState()方法中被调用。

private void setScrollState(int newState) {
    if (mScrollState == newState) {
        return;
    }

    mScrollState = newState;
    if (mPageTransformer != null) {
        // PageTransformers can do complex things that benefit from hardware layers.
        enableLayers(newState != SCROLL_STATE_IDLE);
    }
    if (mOnPageChangeListener != null) {
        mOnPageChangeListener.onPageScrollStateChanged(newState);
    }
}

我们可以看到,当滚动状态是SCROLL_STATE_IDLE的时候,硬件层被关闭,否则将开启硬件层。这是一个非常好的优化,特别是当ViewPager使用PagerTransformer的时候。使用 PagerTransformer意味着给ViewPager的pages提供了一种自定义出入动画的能力(源码),正因如此,使用硬件层是一个明智的选择。

但是,如果PagerTransformer在ViewPager滑动的时候改变了page的view呢?

自定义的PagerTransformer可能会在view滚动的时候加深view的背景颜色,也可能会改变view内部的组件。在这种情况下,硬件层会在每一帧下都进行更新。这就是为什么我的APP会在滚动的时候变成绿色——我的PagerTransformer改变了滚动的view。

我们现在找到了问题所在,但是要怎么解决呢?首先我的想法是重写我在文章上面所提到关于ViewPager的那几个方法,但是很可惜不可以,因为它们都是private的。不过我可以换一种解决思路:注意观察,在setScrollState()方法中,调用enableLayers()方法之后,还接着调用了mOnPagerChangeListener.onPageScrollStateChanged()方法,所以我所做的就是当滚动状态不是SCROLL_STATE_IDLE的时候,在listener中重置所有ViewPager的子View的LayerType为null。

@Override
public void onPageScrollStateChanged(int scrollState) {
    // A small hack to remove the HW layer that the viewpager add to each page when scrolling.
    if (scrollState != ViewPager.SCROLL_STATE_IDLE) {
        final int childCount = <your_viewpager>.getChildCount();
        for (int i = 0; i < childCount; i++)
            <your_viewpager>.getChildAt(i).setLayerType(View.LAYER_TYPE_NONE, null);
    }
}

这种情况下,在ViewPager#setScrollState()方法设置了ViewPager的子View的LayerType之后,我将它们重置为了null来禁用硬件层。

问题解决了!当我滑动ViewPager的时候,再也不会出现绿色了。

解决这个问题之后,我决定把它上报给谷歌,因为我觉得肯定会有更好的方法,比如通过某种setter在ViewPager滚动的时候来禁用硬件层。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值