LiveWallpaper与SurfaceHolder.lockCanvas(矩形脏) [英] LiveWallpaper with SurfaceHolder.lockCanvas(Rect dirty)

查看:148
本文介绍了LiveWallpaper与SurfaceHolder.lockCanvas(矩形脏)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想请教一下在此被一次或两次解决的问题,但没有我发现能帮助我解决这个问题的信息我遇到了前几天。

我想打一个动态壁纸为Android使用画布 - 它不是以图形复杂到需要的OpenGL。为简单起见假设它由坚实的背景和两个较小的矩形。
绘图包括三个不同的阶段(在单线程):


  1. backgroundDraw()请求整个画布锁,并借鉴了它的纯色

  2. DRAW1()请求部分(矩形R1)锁,并提请只在锁定的矩形

  3. DRAW2()请求部分(矩形R2)锁,并提请只在锁定的矩形

我测试了多个版本的Andr​​oid(包括仿真器和设备):2.1,2.2,2.3.3。这似乎是只有在后者(这里正常工作: http://home.elka.pw.edu.pl/~pgawron/include/Android/android_233.jpg )。在previous的Andr​​oid版本SurfaceHolder.lockCanvas(矩形脏)重新调整使用它结果绘制整个屏幕(这里作为参数传递脏到全屏幕大小,并进一步拉伸(!)的 http://home.elka.pw.edu.pl/~pgawron/include/Android/android_22 .JPG )。我其实可以看到每个矩形被虐待的绘制(全屏):整个屏幕非常迅速改变它的颜色

不幸谷歌无法找到我lockCanvas(矩形脏)使用的任何适当的例子。下面我附上用于测试我的完整和唯一的类。全部Eclipse项目是可访问的流向何方提供的截图放在

我将非常感激,如果有人能最终帮助我,纠正我的code(如果只有这个问题是在我的code)。我真的浪费了太多的时间。

BR

彼得雷利

 包sec.polish code.TEST;进口android.graphics.Canvas;
进口android.graphics.Color;
进口android.graphics.Paint;
进口android.graphics.Rect;
进口android.os.SystemClock;
进口android.service.wallpaper.WallpaperService;
进口android.util.Log;
进口android.view.SurfaceHolder;公共类TestLiveWallpaper扩展WallpaperService {@覆盖
公共引擎onCreateEngine(){
    返回新MyEngine();
}类MyEngine扩展引擎实现SurfaceHolder.Callback {    私人最终字符串LOGTAG = MyEngine.class.getSimpleName();
    私人油漆backgroundPaint =新的油漆();
    私人油漆mPaint1 =新的油漆();
    私人油漆mPaint2 =新的油漆();
    私人长期lastVisibilityOnChange;    私人最终矩形R1 =新的Rect(20,20,60,280);
    私人最终矩形R2 =新的矩形(70,20,110,280);    公共MyEngine(){        。getSurfaceHolder()的addCallback(本);        backgroundPaint.setColor(Color.YELLOW);
        mPaint1.setColor(Color.LTGRAY);
        mPaint2.setColor(Color.MAGENTA);
    }    @覆盖
    公共无效surfaceChanged(SurfaceHolder为arg0,ARG1 INT,INT ARG2,
            INT ARG3){
        drawSurface();
    }    @覆盖
    公共无效surfaceCreated(SurfaceHolder为arg0){
        Log.i(LOGTAGsurfaceCreated);
    }    @覆盖
    公共无效surfaceDestroyed(SurfaceHolder为arg0){
        Log.i(LOGTAGsurfaceDestroyed);
    }    @覆盖
    公共无效的onCreate(SurfaceHolder surfaceHolder){
        super.onCreate(surfaceHolder);        setTouchEventsEnabled(真);
    }    @覆盖
    公共无效onVisibilityChanged(布尔可见){
        如果(!可见)
            返回;        lastVisibilityOnChange = SystemClock.elapsedRealtime();
        drawSurface();
    }    @覆盖
    公共无效onOffsetsChanged(浮动xOffset,浮yOffset,浮XSTEP,
            浮yStep,诠释XPIXELS,诠释YPIXELS){        如果(SystemClock.elapsedRealtime() - lastVisibilityOnChange→30)
            返回;        Log.i(LOGTAGonOffsetsChanged过滤);
        drawSurface();
    }    私人无效drawSurface(){
        backgroundDraw();
        DRAW1();
        DRAW2();
    }    私人无效backgroundDraw(){
        最终SurfaceHolder支架= getSurfaceHolder();        帆布C = NULL;
        尝试{
            C = holder.lockCanvas();
            如果(C!= NULL){
                c.drawRect(holder.getSurfaceFrame(),backgroundPaint);
            }
        } {最后
            如果(C!= NULL)
                holder.unlockCanvasAndPost(C);
        }
    }    私人无效DRAW1(){
        最终SurfaceHolder支架= getSurfaceHolder();        帆布C = NULL;
        尝试{
            C = holder.lockCanvas(R1);
            如果(C!= NULL){
                c.drawRect(R1,mPaint1);
            }
        } {最后
            如果(C!= NULL)
                holder.unlockCanvasAndPost(C);
        }
    }    私人无效DRAW2(){
        最终SurfaceHolder支架= getSurfaceHolder();        帆布C = NULL;
        尝试{
            C = holder.lockCanvas(R2);
            如果(C!= NULL){
                c.drawRect(R2,mPaint2);
            }
        } {最后
            如果(C!= NULL)
                holder.unlockCanvasAndPost(C);
        }
    }
}
}


解决方案

lockCanvas(矩形脏)是pretty简单。请记住,在Android上表面是默认双缓冲。这意味着你不仅需要重绘当前表面的脏区,而且previous表面的脏区,使其正常工作。这就是为什么lockCanvas()将调整您通过矩形:它告诉我们真正的脏区是什么。肮脏的地区也可能发生变化,因为表面被丢弃并重新创建等使用lockCanvas(矩形)正确的做法是通过你的脏矩形,然后检查它的新的价值观和孝敬他们。

I would like to ask about a problem that has been addressed here once or twice, but none of information I found could help me overcome the problem I faced a few days ago.

I want to make a live wallpaper for android using canvases - it is not graphically complicated enough to require OpenGL. For simplicity assume it consists of solid background and two smaller rectangles. Drawing consists of three separate stages (in single thread):

  1. backgroundDraw() requests entire canvas lock and draws on it solid color
  2. draw1() requests partial (Rect r1) lock and draws only on locked rectangle
  3. draw2() requests partial (Rect r2) lock and draws only on locked rectangle

I tested it on multiple Android versions (both emulators and devices): 2.1, 2.2, 2.3.3. It seems to be working properly only on the latter one (here: http://home.elka.pw.edu.pl/~pgawron/include/Android/android_233.jpg). On previous Android versions SurfaceHolder.lockCanvas(Rect dirty) resizes(!) dirty passed as parameter to size of the full screen and further drawing using it results drawing on the whole screen (here: http://home.elka.pw.edu.pl/~pgawron/include/Android/android_22.jpg). I can in fact see how each rectangle is being ill-drawn (full-screen): whole screen changes it's color very quickly.

Unluckily google could not find for me any proper example of lockCanvas(Rect dirty) usage. Below I attach my complete and only class used for testing purposes. Full eclipse project is accessible just where provided screenshots are placed.

I would be extremely grateful if somebody could finally help me and correct my code (if only the problem is in my code). I really wasted too much time on it.

BR,

petrelli

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, 20, 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) is pretty simple. Remember that on Android surfaces are double-buffered by default. This means that you need to not only repaint the dirty region of the current surface, but also the dirty region of the previous surface to make it work properly. This is why lockCanvas() will resize the rectangle you pass: it tells what the real dirty region is. The dirty region might also change because the surface was discarded and recreated, etc. The correct way to use lockCanvas(Rect) is to pass your dirty rectangle and then check its new values and honor them.

这篇关于LiveWallpaper与SurfaceHolder.lockCanvas(矩形脏)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆