android – LiveWallpaper与SurfaceHolder.lockCanvas(Rect脏)

我想问一下这里已经解决过一两次的问题,但我发现的任何信息都无法帮助我克服几天前遇到的问题.

我想使用画布为Android制作一个动态壁纸 – 它的图形复杂程度不足以要求OpenGL.为简单起见,假设它由实心背景和两个较小的矩形组成.
绘图由三个独立的阶段组成(单线程):

> backgroundDraw()请求整个画布锁并在其上绘制纯色
> draw1()请求部分(Rect r1)锁定并仅在锁定的矩形上绘制
> draw2()请求部分(Rect r2)锁定并仅在锁定的矩形上绘制

我在多个Android版本(模拟器和设备)上测试了它:2.1,2.2,2.3.3.它似乎只适用于后者(这里:http://home.elka.pw.edu.pl/~pgawron/include/Android/android_233.jpg).在以前的Android版本中,SurfaceHolder.lockCanvas(Rect dirty)调整大小(!)脏参数作为参数传递给全屏的大小,并使用它进一步绘制结果在整个屏幕上绘制(此处:http://home.elka.pw.edu.pl/~pgawron/include/Android/android_22.jpg).事实上,我可以看到每个矩形是如何被绘制的(全屏):整个屏幕很快就会改变它的颜色.

不幸的是谷歌找不到任何关于lockCanvas(Rect脏)用法的正确例子.下面我附上我用于测试目的的完整且唯一的类.可以在提供屏幕截图的位置访问完整的eclipse项目.

如果有人能够最终帮助我并更正我的代码(如果我的代码中只有问题),我将非常感激.我真的浪费了太多时间.

BR,

彼得雷利

package sec.polishcode.test;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.SystemClock;
import android.service.wallpaper.WallpaperService;
import android.util.Log;
import android.view.SurfaceHolder;

public class TestLiveWallpaper extends WallpaperService{

@Override
public Engine onCreateEngine() {
    return new MyEngine();
}

class MyEngine extends Engine implements SurfaceHolder.Callback {

    private final String LOGTAG = MyEngine.class.getSimpleName();
    private Paint backgroundPaint = new Paint();
    private Paint mPaint1 = new Paint();
    private Paint mPaint2 = new Paint();
    private long lastVisibilityOnChange;

    private final Rect r1 = new Rect(20,20,60,280);
    private final Rect r2 = new Rect(70,110,280);

    public MyEngine() {

        getSurfaceHolder().addCallback(this);

        backgroundPaint.setColor(Color.YELLOW);
        mPaint1.setColor(Color.LTGRAY);
        mPaint2.setColor(Color.magenta);
    }

    @Override
    public void surfaceChanged(SurfaceHolder arg0,int arg1,int arg2,int arg3) {
        drawSurface();
    }

    @Override
    public void surfaceCreated(SurfaceHolder arg0) {
        Log.i(LOGTAG,"surfaceCreated");
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder arg0) {
        Log.i(LOGTAG,"surfaceDestroyed");
    }

    @Override
    public void onCreate(SurfaceHolder surfaceHolder) {
        super.onCreate(surfaceHolder);

        setTouchEventsEnabled(true);
    }

    @Override
    public void onVisibilityChanged(boolean visible) {
        if (!visible)
            return;

        lastVisibilityOnChange = SystemClock.elapsedRealtime();
        drawSurface();
    }

    @Override
    public void onOffsetsChanged(float xOffset,float yOffset,float xStep,float yStep,int xPixels,int yPixels) {

        if (SystemClock.elapsedRealtime() - lastVisibilityOnChange > 30)
            return;

        Log.i(LOGTAG,"onOffsetsChanged filtered");
        drawSurface();
    }

    private void drawSurface() {
        backgroundDraw();
        draw1();
        draw2();
    }

    private void backgroundDraw() {
        final SurfaceHolder holder = getSurfaceHolder();

        Canvas c = null;
        try {
            c = holder.lockCanvas();
            if (c != null) {
                c.drawRect(holder.getSurfaceFrame(),backgroundPaint);
            }
        } finally {
            if (c != null)
                holder.unlockCanvasAndPost(c);
        }
    }

    private void draw1() {
        final SurfaceHolder holder = getSurfaceHolder();

        Canvas c = null;
        try {
            c = holder.lockCanvas(r1);
            if (c != null) {
                c.drawRect(r1,mPaint1);
            }
        } finally {
            if (c != null)
                holder.unlockCanvasAndPost(c);
        }
    }

    private void draw2() {
        final SurfaceHolder holder = getSurfaceHolder();

        Canvas c = null;
        try {
            c = holder.lockCanvas(r2);
            if (c != null) {
                c.drawRect(r2,mPaint2);
            }
        } finally {
            if (c != null)
                holder.unlockCanvasAndPost(c);
        }
    }
}
}
最佳答案
lockCanvas(Rect dirty)非常简单.请记住,Android表面认为双缓冲.这意味着您不仅需要重新绘制当前曲面的脏区域,还需要重绘前一曲面的脏区域以使其正常工作.这就是为什么lockCanvas()会调整你传递的矩形的大小:它告诉真正的脏区域是什么.脏区域也可能会更改,因为表面被丢弃并重新创建等等.使用lockCanvas(Rect)的正确方法是传递脏矩形,然后检查其新值并遵守它们.

相关文章

Android性能优化——之控件的优化 前面讲了图像的优化,接下...
前言 上一篇已经讲了如何实现textView中粗字体效果,里面主要...
最近项目重构,涉及到了数据库和文件下载,发现GreenDao这个...
WebView加载页面的两种方式 一、加载网络页面 加载网络页面,...
给APP全局设置字体主要分为两个方面来介绍 一、给原生界面设...
前言 最近UI大牛出了一版新的效果图,按照IOS的效果做的,页...