RE:动态壁纸屏幕旋转

时间:2012-06-19 15:57:12

标签: android live-wallpaper screen-rotation

我最近在我的动态壁纸中发布了一个关于屏幕旋转的问题。为了测试我遇到这些问题的原因,我在下面创建了简单的程序:

package com.live.waller;

import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Handler;
import android.service.wallpaper.WallpaperService;
import android.view.MotionEvent;
import android.view.SurfaceHolder;

public class LiveWallpaperService extends WallpaperService {


/** Called when the activity is first created. */

@Override
public Engine onCreateEngine() {
    // TODO Auto-generated method stub
    return new LiveWallerEngine();
}


class LiveWallerEngine extends Engine {

    SurfaceHolder holder;
    private Handler mHandle;

    LiveWallerEngine() {
        mHandle = new Handler();
        holder = getSurfaceHolder();
    }


    private Runnable runner = new Runnable() {

        public void run() {
            // TODO Auto-generated method stub
            drawFrame();
        }

    };

    public void drawFrame() {
        while(isVisible()) {
            if(!holder.getSurface().isValid())
                continue;

            Canvas c = null;

            try{
                c = holder.lockCanvas();

                drawSurface(c);
            } finally {
                if(c != null) holder.unlockCanvasAndPost(c);
            }
        }
    }

    public void drawSurface(Canvas c) {


        c.save();

        c.drawColor(Color.argb(255, 100, 200, 124));

        c.restore();

    }

    @Override
    public void onCreate(SurfaceHolder surfaceHolder) {
        // TODO Auto-generated method stub
        super.onCreate(surfaceHolder);

        setTouchEventsEnabled(true);
        mHandle.post(runner);

    }

    @Override
    public void onOffsetsChanged(float xOffset, float yOffset,
            float xOffsetStep, float yOffsetStep, int xPixelOffset,
            int yPixelOffset) {
        // TODO Auto-generated method stub
        super.onOffsetsChanged(xOffset, yOffset, xOffsetStep, yOffsetStep,
                xPixelOffset, yPixelOffset);
    }

    @Override
    public void onSurfaceChanged(SurfaceHolder holder, int format,
            int width, int height) {
        // TODO Auto-generated method stub
        super.onSurfaceChanged(holder, format, width, height);

        mHandle.post(runner);
    }

    @Override
    public void onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
        super.onTouchEvent(event);
    }

    @Override
    public void onVisibilityChanged(boolean visible) {
        // TODO Auto-generated method stub
        super.onVisibilityChanged(visible);

    }

    @Override
    public void setTouchEventsEnabled(boolean enabled) {
        // TODO Auto-generated method stub
        super.setTouchEventsEnabled(enabled);
    }   
}

}

当我旋转壁纸时,我会看到一个空白屏幕。有谁知道我的代码出了什么问题?

当我运行壁纸时,我在logcat中收到这些错误:

ActivityManager: force stopping package com.live.waller uid=10046
PackageManager: Not granting permission android.permission.BIND_WALLPAPER to package com.live.waller (protectionLevel=3 flags=0xbe46)
dalvikvm: GC_CONCURRENT freed 609K, 43% free 4604K/8071K, external 904K/1222K, paused 6ms+7ms
dalvikvm: GC_EXPLICIT freed 320K, 44% free 4561K/8071K, external 904K/1222K, paused 138ms
dalvikvm: GC_EXTERNAL_ALLOC freed 197K, 51% free 2955K/6023K, external 1736K/1742K, paused 78ms

奇怪的是,当我设置壁纸时,我在logcat中收到强制停止消息,但在模拟器上没有。

1 个答案:

答案 0 :(得分:2)

只要isVisible()返回true,drawFrame()方法就会陷入无限循环。当你得到一个带有处理程序的Runnable时,不需要while语句来循环锁定和发布你刚刷过的画布。

可以在SDK的Cube Live Wallpaper示例中找到更好的drawFrame()实现。

private void drawFrame() {
    Canvas c = null;

    try {
        // Get a Canvas from the surfaceHolder, so we got something to paint on
        c = holder.lockCanvas();

        // Make sure we got a valid (non-null) canvas.
        if(c != null) {
            // Draw something onto the canvas
            drawSurface(c);
        }
    } finally {
        if(c != null) 
            // Notify the SurfaceHolder that we are done painting the canvas,
            // and we want it shown on the screen
            holder.unlockCanvasAndPost(c);
    }

    // If your wallpaper is going to have animated objects, you will have to tell
    // the handler to schedule new runs on your Runnable object.

    // First we remove any pending task in the Handlers message queue
    mHandle.removeCallbacks(runner);

    // Then we tell the Handler to schedule a new run some time in the future. The 
    // time we specify here will decide how often the screen updates, or in other words
    // the FPS of your wallpaper. If the wallpaper is not visible, there is no reason to update wallpaper. So we only schedule a new run, if mIsVisible is true.    
    if(mIsVisible) { 
        mHandle.postDelayed(runner, 1000 / desiredFPS);
    }
}

现在,我们使用Engine.onVisibilityChanged()来判断壁纸是否可见。

@Override
public void onVisibilityChanged(boolean visible) {
    // Set mIsVisible equal to visible, so that drawFrame() can decide wheter to reschedule run or not.
    mIsVisible = visible;

    if (visible) {
        // Since drawFrame() tells the handler to schedule new runs, we only need to call drawFrame() once. In drawFrame(), mHandle.postDelayed() will then continuously update the screen, as long as its visible.
        drawFrame();
    } else {
        // If not, remove any pending posts, since we no longer need to update the wallpaper.
        mHandle.removeCallbacks(runner);
    }
}

如果我们绘制的Surface以某种方式被破坏(例如:如果用户设置了新的背景),我们还想删除所有待处理的帖子。所以在Engine.onSurfaceDestroyed()中,我们做

@Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
    super.onSurfaceDestroyed(holder);
    mHandle.removeCallbacks(runner);
}

关于部队关闭问题: 您尝试运行壁纸的API级别是什么?