|
Android example source code file (CanvasSurfaceView.java)
The CanvasSurfaceView.java Android example source code
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.spritemethodtest;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
/**
* Implements a surface view which writes updates to the surface's canvas using
* a separate rendering thread. This class is based heavily on GLSurfaceView.
*/
public class CanvasSurfaceView extends SurfaceView
implements SurfaceHolder.Callback {
private boolean mSizeChanged = true;
private SurfaceHolder mHolder;
private CanvasThread mCanvasThread;
public CanvasSurfaceView(Context context) {
super(context);
init();
}
public CanvasSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_NORMAL);
}
public SurfaceHolder getSurfaceHolder() {
return mHolder;
}
/** Sets the user's renderer and kicks off the rendering thread. */
public void setRenderer(Renderer renderer) {
mCanvasThread = new CanvasThread(mHolder, renderer);
mCanvasThread.start();
}
public void surfaceCreated(SurfaceHolder holder) {
mCanvasThread.surfaceCreated();
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return
mCanvasThread.surfaceDestroyed();
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// Surface size or format has changed. This should not happen in this
// example.
mCanvasThread.onWindowResize(w, h);
}
/** Inform the view that the activity is paused.*/
public void onPause() {
mCanvasThread.onPause();
}
/** Inform the view that the activity is resumed. */
public void onResume() {
mCanvasThread.onResume();
}
/** Inform the view that the window focus has changed. */
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
mCanvasThread.onWindowFocusChanged(hasFocus);
}
/**
* Set an "event" to be run on the rendering thread.
* @param r the runnable to be run on the rendering thread.
*/
public void setEvent(Runnable r) {
mCanvasThread.setEvent(r);
}
/** Clears the runnable event, if any, from the rendering thread. */
public void clearEvent() {
mCanvasThread.clearEvent();
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mCanvasThread.requestExitAndWait();
}
protected void stopDrawing() {
mCanvasThread.requestExitAndWait();
}
// ----------------------------------------------------------------------
/** A generic renderer interface. */
public interface Renderer {
/**
* Surface changed size.
* Called after the surface is created and whenever
* the surface size changes. Set your viewport here.
* @param width
* @param height
*/
void sizeChanged(int width, int height);
/**
* Draw the current frame.
* @param canvas The target canvas to draw into.
*/
void drawFrame(Canvas canvas);
}
/**
* A generic Canvas rendering Thread. Delegates to a Renderer instance to do
* the actual drawing.
*/
class CanvasThread extends Thread {
private boolean mDone;
private boolean mPaused;
private boolean mHasFocus;
private boolean mHasSurface;
private boolean mContextLost;
private int mWidth;
private int mHeight;
private Renderer mRenderer;
private Runnable mEvent;
private SurfaceHolder mSurfaceHolder;
CanvasThread(SurfaceHolder holder, Renderer renderer) {
super();
mDone = false;
mWidth = 0;
mHeight = 0;
mRenderer = renderer;
mSurfaceHolder = holder;
setName("CanvasThread");
}
@Override
public void run() {
boolean tellRendererSurfaceChanged = true;
/*
* This is our main activity thread's loop, we go until
* asked to quit.
*/
final ProfileRecorder profiler = ProfileRecorder.sSingleton;
while (!mDone) {
profiler.start(ProfileRecorder.PROFILE_FRAME);
/*
* Update the asynchronous state (window size)
*/
int w;
int h;
synchronized (this) {
// If the user has set a runnable to run in this thread,
// execute it and record the amount of time it takes to
// run.
if (mEvent != null) {
profiler.start(ProfileRecorder.PROFILE_SIM);
mEvent.run();
profiler.stop(ProfileRecorder.PROFILE_SIM);
}
if(needToWait()) {
while (needToWait()) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
if (mDone) {
break;
}
tellRendererSurfaceChanged = mSizeChanged;
w = mWidth;
h = mHeight;
mSizeChanged = false;
}
if (tellRendererSurfaceChanged) {
mRenderer.sizeChanged(w, h);
tellRendererSurfaceChanged = false;
}
if ((w > 0) && (h > 0)) {
// Get ready to draw.
// We record both lockCanvas() and unlockCanvasAndPost()
// as part of "page flip" time because either may block
// until the previous frame is complete.
profiler.start(ProfileRecorder.PROFILE_PAGE_FLIP);
Canvas canvas = mSurfaceHolder.lockCanvas();
profiler.start(ProfileRecorder.PROFILE_PAGE_FLIP);
if (canvas != null) {
// Draw a frame!
profiler.start(ProfileRecorder.PROFILE_DRAW);
mRenderer.drawFrame(canvas);
profiler.stop(ProfileRecorder.PROFILE_DRAW);
profiler.start(ProfileRecorder.PROFILE_PAGE_FLIP);
mSurfaceHolder.unlockCanvasAndPost(canvas);
profiler.stop(ProfileRecorder.PROFILE_PAGE_FLIP);
}
}
profiler.stop(ProfileRecorder.PROFILE_FRAME);
profiler.endFrame();
}
}
private boolean needToWait() {
return (mPaused || (! mHasFocus) || (! mHasSurface) || mContextLost)
&& (! mDone);
}
public void surfaceCreated() {
synchronized(this) {
mHasSurface = true;
mContextLost = false;
notify();
}
}
public void surfaceDestroyed() {
synchronized(this) {
mHasSurface = false;
notify();
}
}
public void onPause() {
synchronized (this) {
mPaused = true;
}
}
public void onResume() {
synchronized (this) {
mPaused = false;
notify();
}
}
public void onWindowFocusChanged(boolean hasFocus) {
synchronized (this) {
mHasFocus = hasFocus;
if (mHasFocus == true) {
notify();
}
}
}
public void onWindowResize(int w, int h) {
synchronized (this) {
mWidth = w;
mHeight = h;
mSizeChanged = true;
}
}
public void requestExitAndWait() {
// don't call this from CanvasThread thread or it is a guaranteed
// deadlock!
synchronized(this) {
mDone = true;
notify();
}
try {
join();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
/**
* Queue an "event" to be run on the rendering thread.
* @param r the runnable to be run on the rendering thread.
*/
public void setEvent(Runnable r) {
synchronized(this) {
mEvent = r;
}
}
public void clearEvent() {
synchronized(this) {
mEvent = null;
}
}
}
}
Other Android examples (source code examples)Here is a short list of links related to this Android CanvasSurfaceView.java source code file: |
| ... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.