-- 双缓冲理解 : http://www.apkbus.com/android-99309-1-1.html 分析SurfaceView源码
-- 双缓冲与单缓冲区别 :  
-- 双缓冲与但缓冲动画绘制区别demo : 

4、Android 双缓冲

所谓双缓冲技术其实很简单:当程序需要在指定View上进行绘制时,程序并不直接绘制到该View组件上,而是先绘制到内存中的一个Bitmap图片(这就是缓冲区)上,等到内存中的Bitmap绘制好之后,再一次性地将Bitmap绘制到View组件上。

       实现思路:

            1).定义一个内存中图片,将他作为缓冲区Bitmap cacheBitmap = null; 
            2).定义缓冲区Cache的Canvas对象 Canvas cacheCanvas = null; 
            3).设置cacheCanvas将会绘制到内存的bitmap上。 cacheCanvas.setBitmap(cacheBitmap);
            4). 将cacheBitmap绘制到该View上.。canvas.drawBitmap(cacheBitmap,0,0,p);

class DrawView extends View {

    float preX;
    float preY;
    private Path path;
    public Paint paint = null;
    final int VIEW_WIDTH = 900;
    final int VIEW_HEIGHT = 1024;
    //定义一个内存中的图片, 该图片将作为缓冲区
    Bitmap cacheBitmap = null;
    //定义cacheBitmap上的Canvas对象
    Canvas cacheCanvas = null;

    public DrawView(Context context, AttributeSet set){
        super(context, set);
        //创建一个与该view相同大小的缓冲区
        cacheBitmap = Bitmap.createBitmap(VIEW_WIDTH, VIEW_HEIGHT, Bitmap.Config.ARGB_8888);
        cacheCanvas = new Canvas();
        path = new Path();
        //设置cacheCanvas将会绘制到内存中的cacheBitmap上
        cacheCanvas.setBitmap(cacheBitmap);

        paint = new Paint(Paint.DITHER_FLAG);
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(1);
        paint.setAntiAlias(true);
        paint.setDither(true);

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                path.moveTo(x, y);
                preX = x;
                preY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                path.quadTo(preX, preY, x, y);
                preX = x ;
                preY = y;
                break;
            case MotionEvent.ACTION_UP:
                cacheCanvas.drawPath(path, paint);
                path.reset();
                break;
        }
       // Log.i("ysong", "调用了invalidate()函数");
        invalidate();
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Paint bmpPaint = new Paint();
        //将cacheBitmap绘制到该View组件上
        canvas.drawBitmap(cacheBitmap, 0, 0, bmpPaint);
        //沿着path绘制
        canvas.drawPath(path, paint);
        //为什么还要绘制一次path???
        //这行代码非常重要,
        //每次手指在屏幕上面移动,path会将轨迹记录下来,然后绘制到缓冲的bitmap上面
        // view 每次调用invalidate()更新的时候,会将bitmap上面缓冲的内容绘制到view上面(也就是canvas)
        // ACTION_MOVE 和 ACTION_DOWN 也会触发invalid()更新view,这个时候path的内容还没有绘制到cacheBitmap上面,
        // 如果没有上面这行canvas.drawPath(path, paint), 效果就会是当手指离开屏幕时,之前绘制的轨迹才会出现,感觉像是慢了半拍
        // 有了上面这一行代码,当ACTION_MOVE手指移动的时候,就会把临时的path绘制到view上面,这样感觉像是画笔随着手指在动
        // 最后再把cacheBitmap的内容绘制到view上面

        //ACTION_MOVE 其实并不是从手指DOWN到UP的过程,其中会触发很多次invalid()函数,
        // ACTION_MOVE其实包含了两个动作,只不是期间的时间间隔非常短, 看起来感觉像是一个动作, 可以通过log来测试一下,看一下移动调用了多少次invalidate()
    }
}