0

最近、ライブ壁紙の画面回転に関する質問を投稿しました。これらの問題が発生した理由をテストするために、以下の簡単なプログラムを作成しました。

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 で強制停止メッセージが表示されることです。

4

1 に答える 1

2

isVisible()がtrueを返す限り、drawFrame()メソッドは無限ループでスタックします。ハンドラー付きのRunnableを取得したときに、ペイントしたばかりのCanvasのロックと投稿をループするwhileステートメントは必要ありません。

drawFrame()のより良い実装は、SDKのCubeLiveWallpaperの例にあります。

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);
    }
}

ペイントしたサーフェスが何らかの理由で破壊された場合(例:ユーザーが新しい背景を設定した場合)、保留中の投稿もすべて削除します。したがって、Engine.onSurfaceDestroyed()では、

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

フォースクローズの問題について:壁紙を実行しようとしているAPIレベルは何ですか?

于 2012-06-19T18:44:31.973 に答える