Android SufraceView - 无法更新Canvas内容

时间:2015-07-11 15:11:47

标签: android android-canvas surfaceview animated-gif

我使用SurfaceViewCanvas开发了带有GIF的壁纸。当GIF必须更新和更改时。但问题是,当更新屏幕的时间变为黑色时。

此处来自WallpaperEngine

的片段
class WallpaperEngine extends Engine implements SharedPreferences.OnSharedPreferenceChangeListener {

private static final String TAG = "WallpaperEngine";
    private AnimationThread animationThread;
    private SurfaceHolder mSurfaceHolder;
    private Scene scene;
    private Movie movie1;
    private Movie movie2;
    private Movie movie3;
    private Movie movie4;
    private Movie movie5;
    private Bitmap bitmap1;
    private Bitmap bitmap2;
    private Bitmap bitmap3;
    private Bitmap bitmap4;
    private BitmapFactory.Options opts, bitmapOptions;
    private SharedPreferences prefs;
    private float dx = 0.0f;
    private int mWidth, mHeight;

    WallpaperManager myWallpaperManager;
    View view;
    WindowManager.LayoutParams lp;

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

        Log.d(TAG, "onCreate");

        mSurfaceHolder = surfaceHolder;

        opts = new BitmapFactory.Options();
        opts.inSampleSize = 2;

        bitmapOptions = new BitmapFactory.Options();
        bitmapOptions.inSampleSize = 1;

        myWallpaperManager = WallpaperManager.getInstance(getApplicationContext());

        prefs = PreferenceManager.getDefaultSharedPreferences(Wallpaper.this);

        prefs.registerOnSharedPreferenceChangeListener(this);

        checkCurrentTime();

        movie1 = Movie.decodeStream(getResources().openRawResource(R.raw.fountain));
        movie2 = Movie.decodeStream(getResources().openRawResource(R.raw.idle_cycle));
        movie3 = Movie.decodeStream(getResources().openRawResource(R.raw.tree_move));
        movie4 = Movie.decodeStream(getResources().openRawResource(R.raw.wash_full));
        movie5 = Movie.decodeStream(getResources().openRawResource(R.raw.prayer_full));

        DisplayMetrics displayMetrics = new DisplayMetrics();
        Display display = ((WindowManager) getBaseContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
        display.getMetrics(displayMetrics);

        mHeight = displayMetrics.heightPixels;
        mWidth  = displayMetrics.widthPixels;

        // create the scene
        scene = new Scene(sky, ground, town, middle, movie1, movie2, movie3, null, null, mHeight);

        // start animation thread; thread starts paused
        // will run onVisibilityChanged
        animationThread = new AnimationThread(mSurfaceHolder, scene);
        animationThread.start();
    }

当需要更改GIF动画时,我调用updateWallpapers()方法:

private void updateWallpapers(int skyId, int townId, int middleId, Movie movie2, Movie movie4, Movie movie5) {

        sky    = BitmapFactory.decodeResource(getResources(), skyId);
        ground = BitmapFactory.decodeResource(getResources(), R.drawable.ground_plainblack, opts);
        town   = BitmapFactory.decodeResource(getResources(), townId);
        middle = BitmapFactory.decodeResource(getResources(), middleId);

        if (movie2 != null) {
            scene = new Scene(sky, ground, town, middle, movie1, movie2, movie3, null, null, mHeight);

        } else if (movie4 != null) {
            scene = new Scene(sky, ground, town, middle, movie1, null, movie3, movie4, null, mHeight);

        } else if (movie5 != null) {
            scene = new Scene(sky, ground, town, middle, movie1, null, movie3, null, movie5, mHeight);
        }
        animationThread.stopThread();
        joinThread(animationThread);
        animationThread = null;
        animationThread = new AnimationThread(mSurfaceHolder, scene);
        animationThread.start();
        animationThread.resumeThread();
    }

AnimationThread上课,我认为这是问题,但我无法解决它:

public class AnimationThread extends Thread {

private static final String TAG = "AnimationThread";

private Object pauseLock = new Object();

private boolean running = true;
private boolean paused = true;

private int fps = 30;
private int timeFrame = 1000 / fps; // drawing time frame in miliseconds 1000 ms / fps

final private SurfaceHolder surfaceHolder;
private Scene scene;

public AnimationThread(SurfaceHolder surfaceHolder, Scene scene) {
    this.surfaceHolder = surfaceHolder;
    this.scene = scene;
}

@Override
public void run() {

    while (running) {

        waitOnPause();

        if (!running) {
            return;
        }

        long beforeDrawTime = System.currentTimeMillis();

        Canvas canvas = null;
        try {

            if (surfaceHolder.getSurface().isValid()) {
                canvas = surfaceHolder.lockCanvas();
               /** Clean Canvas before draw. 
                   When I erase this line screen not changing and it draws GIFs above each other, layer by layer. 
                   But now when I update GIFs screen just turns black and freezes on this state.  
                   HERE'S THE PROBLEM!!! */
                canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.MULTIPLY);
            }
            /** Workaround for: SurfaceTextureClient: dequeueBuffer failed (No such device) */
            if (canvas == null) {
                continue;
            }
            synchronized (surfaceHolder) {
                scene.draw(canvas);
            }

        } catch (IllegalArgumentException e) {
            Log.e(TAG, "Error during surfaceHolder.lockCanvas()", e);
            stopThread();
        } finally {
            if (canvas != null) {
                try {
                    surfaceHolder.unlockCanvasAndPost(canvas);
                } catch (IllegalArgumentException e) {
                    Log.e(TAG, "Error during unlockCanvasAndPost()", e);
                    stopThread();
                }
            }
        }

        long afterDrawTime = System.currentTimeMillis() - beforeDrawTime;
        try {
            if (timeFrame > afterDrawTime) {
                Thread.sleep(timeFrame - afterDrawTime);
            }
        } catch (InterruptedException ex) {
            Log.e(TAG, "Exception during Thread.sleep().", ex);
        }

    }

}

public void stopThread() {
    synchronized (pauseLock) {
        paused = false;
        running = false;
        pauseLock.notifyAll();
    }
    Log.d(TAG, "Stopped thread (" + this.getId() + ")");
}

public void pauseThread() {
    synchronized (pauseLock) {
        paused = true;
    }
    Log.d(TAG, "Paused thread (" + this.getId() + ")");
}

public void resumeThread() {
    synchronized (pauseLock) {
        paused = false;
        pauseLock.notifyAll();
    }
    Log.d(TAG, "Resumed thread (" + this.getId() + ")");
}

private void waitOnPause() {
    synchronized (pauseLock) {
        while (paused) {
            try {
                pauseLock.wait();
            } catch (InterruptedException e) {
            }
        }
    }
}

}

Scene上课:

public class Scene {

private Bitmap background = null;
private Bitmap ground = null;
private Bitmap town = null;
private Bitmap middle = null;
private Movie movie1 = null;
private Movie movie2 = null;
private Movie movie3 = null;
private Movie movie4 = null;
private Movie movie5 = null;
private Rect rectangleFrame = null;
private int height;
private int width;
private float dx;

private int centerX;
private int centerY;

public Scene(Bitmap backgroundImg, Bitmap groundImg, Bitmap townImg, Bitmap middleImg,
             Movie movie1, Movie movie2, Movie movie3 Movie movie4,
             Movie movie5, int screenHeight) {

    background  = backgroundImg;
    town        = townImg;
    middle      = middleImg;
    ground      = groundImg;
    height      = screenHeight;
    this.movie1 = movie1;
    this.movie2 = movie2;
    this.movie3 = movie3;
    this.movie3 = movie4;
    this.movie4 = movie5;
}

public synchronized void updateSize(int width, int height, float dx) {

    this.dx = dx;
    centerY = height / 2;

    this.height = height;
    this.width = width;
}

public synchronized void draw(Canvas canvas) {

    canvas.save();
    canvas.translate(dx, 0);

    rectangleFrame = new Rect(0, 0, (int) (this.width * 2.5), this.height);
    centerX = rectangleFrame.centerX() / 2;

    canvas.drawBitmap(background, null, rectangleFrame, null);

    canvas.drawBitmap(town, null, rectangleFrame, null);

    canvas.drawBitmap(middle, null, rectangleFrame, null);

    canvas.drawBitmap(ground, null, rectangleFrame, null);

    movie1.draw(canvas, centerX - (movie3.width() / 2),
            (rectangleFrame.centerY() + (rectangleFrame.centerY() / 1.65f)) - this.movie1.height());

    if (movie2 != null) {
        movie2.draw(canvas, centerX,
                (rectangleFrame.centerY() + (rectangleFrame.centerY() / 1.6f)) - movie2.height());
    }
    if (movie4 != null) {
        movie4.draw(canvas, centerX - (movie3.width() / 2 - this.movie1.width() + 30),
                (rectangleFrame.centerY() + (rectangleFrame.centerY() / 1.6f)) - movie4.height());
    }
    if (movie5 != null) {
        movie5.draw(canvas, centerX,
                (rectangleFrame.centerY() + (rectangleFrame.centerY() / 1.6f)) - movie5.height());
    }

    movie3.draw(canvas, centerX + this.movie1.width(),
            (rectangleFrame.centerY() + (rectangleFrame.centerY() / 1.6f)) - movie3.height());

    canvas.restore();

    this.movie1.setTime((int) (System.currentTimeMillis() % this.movie1.duration()));

    if (movie2 != null) {
        movie2.setTime((int) (System.currentTimeMillis() % movie2.duration()));
    }
    if (movie4 != null) {
        movie4.setTime((int) (System.currentTimeMillis() % movie4.duration()));
    }
    if (movie5 != null) {
        movie5.setTime((int) (System.currentTimeMillis() % movie5.duration()));
    }
    movie3.setTime((int) (System.currentTimeMillis() % movie3.duration()));

}

任何帮助将不胜感激!谢谢!

1 个答案:

答案 0 :(得分:0)

在我的代码上花了很多时间后,我终于找到了解决方案!我刚删除了这一行canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.MULTIPLY);并在updateSize()实施后添加了AnimationThread方法,如下所示:

animationThread.stopThread();
joinThread(animationThread);
animationThread = null;
animationThread = new AnimationThread(mSurfaceHolder, scene);
animationThread.start();
animationThread.resumeThread();
/**----------------Here!!!---------------*/
scene.updateSize(mWidth, mHeight, dx);

现在它运作正常!