Android在绘制过程中,为了提高一些复杂View的绘制效率,可以对View做缓存。
Android提供个两种缓存,硬件缓冲和软件缓冲。软件缓冲就是将View缓冲成一个bitmap,而硬件缓冲就是将View缓冲到一个Frame Buffer Object中。详见:
http://blog.csdn.net/mapdigit/article/details/7686962
我们从View的buildLayer方法开始分析为View建立缓存的过程:
/**
* Forces this view's layer to be created and this view to be rendered
* into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE},
* invoking this method will have no effect.
*
* This method can for instance be used to render a view into its layer before
* starting an animation. If this view is complex, rendering into the layer
* before starting the animation will avoid skipping frames.
*
* @throws IllegalStateException If this view is not attached to a window
*
* @see #setLayerType(int, android.graphics.Paint)
*/
public void buildLayer() {
if (mLayerType == LAYER_TYPE_NONE) return;
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo == null) {
throw new IllegalStateException("This view must be attached to a window first");
}
switch (mLayerType) {
case LAYER_TYPE_HARDWARE:
if (attachInfo.mHardwareRenderer != null &&
attachInfo.mHardwareRenderer.isEnabled() &&
attachInfo.mHardwareRenderer.validate()) {
getHardwareLayer();
// TODO: We need a better way to handle this case
// If views have registered pre-draw listeners they need
// to be notified before we build the layer. Those listeners
// may however rely on other events to happen first so we
// cannot just invoke them here until they don't cancel the
// current frame
if (!attachInfo.mTreeObserver.hasOnPreDrawListeners()) {
attachInfo.mViewRootImpl.dispatchFlushHardwareLayerUpdates();
}
}
break;
case LAYER_TYPE_SOFTWARE:
buildDrawingCache(true);
break;
}
}
官方对方法的解释是:强制View创建自己对应的层,并将自己绘制到层上,如果层的类型是LAYER_TYPE_NONE,那么该函数将不起作用。所以该方法要和setLayerType(int layerType, Paint paint)方法配合使用。
public void setLayerType(int layerType, Paint paint) {
......
mLayerType = layerType;
final boolean layerDisabled = mLayerType == LAYER_TYPE_NONE;
mLayerPaint = layerDisabled ? null : (paint == null ? new Paint() : paint);
mLocalDirtyRect = layerDisabled ? null : new Rect();
invalidateParentCaches();
invalidate(true);
}
我们再回到buildLayer函数,如果我们设置了View的层类型是LAYER_TYPE_HARDWARE,就会调用getHardwareLayer()方法;而如果我们设置了View的层次类型是LAYER_TYPE_SOFTWARE,就会调用buildDrawingCache(true)方法。
一、View的硬件层缓存
我们先看getHardwareLayer()方法:
/**
* <p>Returns a hardware layer that can be used to draw this view again
* without executing its draw method.</p>
*
* @return A HardwareLayer ready to render, or null if an error occurred.
*/
HardwareLayer getHardwareLayer() {
......
if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || mHardwareLayer == null) {
if (mHardwareLayer == null) {
mHardwareLayer = mAttachInfo.mHardwareRenderer.createHardwareLayer(
width, height, isOpaque());
mLocalDirtyRect.set(0, 0, width, height);
} else {
......
}
// The layer is not valid if the underlying GPU resources cannot be allocated
if (!mHardwareLayer.isValid()) {
return null;
}
mHardwareLayer.setLayerPaint(mLayerPaint);
mHardwareLayer.redrawLater(getHardwareLayerDisplayList(mHardwareLayer), mLocalDirtyRect);
ViewRootImpl viewRoot = getViewRootImpl();
if (viewRoot != null) viewRoot.pushHardwareLayerUpdate(mHardwareLayer);
mLocalDirtyRect.setEmpty();
}
return mHardwareLayer;
}
该方法就是为View创建一个硬件层。首先会判读是否为该View创建过硬件层,如果没有,就会调用mAttachInfo.mHardwareRenderer.createHardwareLayer( width, height, isOpaque())方法创建一个:
@Override
public HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
return new GLES20RenderLayer(width, height, isOpa