I created a toy app that demos my problem ... the complete code can be
found here: http://www.smileproject.com/SurfCodeExample.zip
Feedback super appreciated. Here is the code from the activity and
view only ...
public class Surf extends Activity {
/** Called when the activity is first created. */
private SurfView mView;
private SurfThread mThread;
private static final int COLOR_MENU_ID = Menu.FIRST;
public static final int ACTIVITY_ASSIGN_COLOR = 0;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mView= new SurfView(this, null);
setContentView(mView);
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
System.out.println ("PAUSED");
mThread.pause();
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
System.out.println ("RESUMED");
mThread = mView.getThread();
mThread.resume();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
boolean result = super.onCreateOptionsMenu(menu);
menu.add(0, COLOR_MENU_ID, 0, R.string.menu_color);
return result;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
switch (item.getItemId()) {
case COLOR_MENU_ID:
Intent i = new Intent(this, SurfChooser.class);
startActivityForResult(i, ACTIVITY_ASSIGN_COLOR);
return true;
}
return true;
}
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
Bundle extras;
if (data == null) return;
extras = data.getExtras();
switch(requestCode) {
case ACTIVITY_ASSIGN_COLOR:
Log.w(this.getClass().getName(), "back");
if (data == null) return;
}
}
}
class SurfView extends SurfaceView implements SurfaceHolder.Callback,
OnGestureListener {
private String TAG = "SurfView";
private boolean is_dirty = true;
private boolean block_block = false;
private boolean block_after_draw = true;
/** The thread that actually draws the animation */
private SurfThread thread;
private GestureDetector mGestureDetector;
public float offset_x = 0; // review this later
public float offset_y = 0;
public float x_velocity = 0; // review this later
public float y_velocity = 0;
private float last_pos_x = 0;
private float last_pos_y = 0;
private int keep_on_trucking = -1;
// used for managing timing in physics
private long start_time = System.currentTimeMillis();
private long end_time = 0;
private long sleep_time = 0;
private long diff_time = 0;
private long action_period = 20; // 50 = 20fps
/** coords of bg circle */
private float bX;
private float bY;
/** coords of pointer (m == mouse). */
private float mX;
private float mY;
/** Handle to the surface manager object we interact with */
private boolean hasSurface;
class SurfThread extends Thread {
private int mCanvasWidth = -1;
private int mCanvasHeight = -1;
/** !!! Message handler used by thread to interact with TextView */
// private Handler mHandler;
/** Used to figure out elapsed time between frames */
private long mLastTime;
/** The state of the game. One of READY, RUNNING, PAUSE,
LOSE, or WIN */
private int mMode;
/** Scratch rect object. */
private RectF mScratchRect;
Paint mPaint = new Paint();
int transparent_white;
/** Indicate whether the surface has been created & is ready to
draw */
private boolean mRunning = false;
public boolean is_drawing = false;
private ConditionVariable mCondition = new ConditionVariable();
private SurfaceHolder mHolder;
private Context mContext;
public SurfThread(SurfaceHolder holder, Context context){
mHolder = holder;
mContext = context;
mRunning = false;
init();
}
public void init(){
mPaint.setColor(Color.RED);
}
public void pause(){
synchronized (this) {
Log.v("PeepThread", "pause?");
//requestExitAndWait();
setRunning(false);
mCondition.open();
//holdup = false;
}
}
public void setRunning(boolean b) {
mRunning = b;
}
public boolean holdup = false;
public void do_draw(){
is_dirty = true;
block_after_draw = true;
mCondition.open();
}
/** this is key to most everything */
@Override
public void run() {
SurfaceHolder surfaceHolder = mHolder;
mCondition = new ConditionVariable(false);
Log.v("Peep Thread", "restarted?");
mRunning = true;
while (mRunning) {
Log.v("Peep Thread", "run?");
while (holdup){
mCondition.block(100);
System.out.println ("not running?");
if (!mRunning){
is_dirty = false;
break;
}
}
is_drawing = true;
updatePhysics();
if (is_dirty){
Canvas c = null;
c = surfaceHolder.lockCanvas(null); // moved this out
of "try" loop as per Stoyan suggestion
try {
synchronized (surfaceHolder) {
draw_me(c);
}
} finally {
// do this in a finally so that if an exception is
thrown
// during the above, we don't leave the Surface in
an
// inconsistent state
if (c != null) {
surfaceHolder.unlockCanvasAndPost(c);
}
}
is_dirty = false;
}
start_time = System.currentTimeMillis();
is_drawing = false;
// !!! this needs to work off a stack
if (block_after_draw) {
mCondition.close();
mCondition.block();
}
}
System.out.println ("thread killed?");
}
public void requestExitAndWait(){
mRunning = false;
try {
join();
} catch (InterruptedException ex){
// nothing is supposed to happen here
// (left intentionally blank)
}
}
/* Callback invoked when the surface dimensions change. */
public void setSurfaceSize(int width, int height) {
// synchronized to make sure these all change atomically
// !!! TODO: make sure center of screen stays. Might make
sense to draw a mini-screen_bubble to confirm.
synchronized (mHolder) {
// this can be improved - ask ben to write something that
will determine the smallest circle that will fit around the largest
square
System.out.println ("setSurfaceSize");
mCanvasWidth = width;
mCanvasHeight = height;
}
}
public void unpause() {
// Move the real time clock up to now
synchronized (mHolder) {
}
thread.do_draw();
}
/**
* Draw operations go in here
*/
private void draw_me(Canvas canvas) {
canvas.drawColor(Color.WHITE); // draw background color
canvas.save();
canvas.translate(offset_x, offset_y);
canvas.drawCircle(mX, mY, 60, mPaint);
canvas.restore();
canvas.translate(offset_x * -1, offset_y * -1);
}
/**
* Figures the lander state (x, y, fuel, ...) based on the passage of
* realtime. Does not invalidate(). Called at the start of draw().
* Detects the end-of-game and sets the UI to the next state.
*/
private void updatePhysics() {
end_time = System.currentTimeMillis();
diff_time = (end_time - start_time);
sleep_time = action_period - diff_time;
if (sleep_time < 1) sleep_time = 1;
try {
Thread.sleep(sleep_time);
}
catch(InterruptedException ex) {
}
is_dirty = true;
}
}
private void init(){
// register our interest in hearing about changes to our surface
mGestureDetector = new GestureDetector(this);
mGestureDetector.setIsLongpressEnabled(false); // true
setLongClickable(false);
hasSurface = false;
}
public SurfView(Context context, AttributeSet attrs) {
super(context, attrs);
init(); // prep stuff for view
SurfaceHolder holder = getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
thread = new SurfThread(holder, context);
}
/**
* Fetches the animation thread corresponding to this View.
*
* @return the animation thread
*/
public SurfThread getThread() {
return thread;
}
/**
* Standard window-focus override. Notice focus lost so we can pause on
* focus lost. e.g. user switches to take a call.
*/
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
}
/* Callback invoked when the surface dimensions change. */
public void surfaceChanged(SurfaceHolder holder, int format, int
width, int height) {
thread.setSurfaceSize(width, height);
// if (thread != null) thread.setSurfaceSize(width, height);
}
/*
* Callback invoked when the Surface has been created and is ready to be
* used.
*/
public void surfaceCreated(SurfaceHolder holder) {
// start the thread here so that we don't busy-wait in run()
// waiting for the surface to be created
is_dirty = true;
Log.w(this.getClass().getName(), thread.isAlive() + "?");
try {
thread.start();
} catch (Exception e){
// thread.run();
System.out.println ("resurfaced"); // DEAL WITH THIS
DIFF
}
}
/*
* Callback invoked when the Surface has been destroyed and must no longer
* be touched. WARNING: after this method returns, the Surface/Canvas must
* never be touched again!
*/
public void surfaceDestroyed(SurfaceHolder holder) {
// we have to tell thread to shut down & wait for it to finish, or else
// it might touch the Surface after we return and explode
boolean retry = true;
thread.setRunning(false);
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
}
}
Log.v(this.getClass().getName(), "SURFACE DESTROYED");
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return false;
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
boolean returnValue = false;
is_dirty = true;
returnValue = mGestureDetector.onTouchEvent(event);
returnValue = returnValue ? returnValue :
onTouchEvent(event);
return returnValue;
}
public boolean onDown(MotionEvent event) {
System.out.println ("down");
thread.do_draw();
return true;
}
public boolean onFling(MotionEvent first_event, MotionEvent
last_event, float velocityX, float velocityY) {
return false;
}
public void onLongPress(MotionEvent event) {
thread.do_draw();
}
public boolean onScroll(MotionEvent arg0, MotionEvent event, float
distance_x, float distance_y) {
return false;
}
public void onShowPress(MotionEvent arg0) {
// TODO Auto-generated method stub
}
public boolean onSingleTapUp(MotionEvent event) {
mX = event.getX();
mY = event.getY();
thread.do_draw();
return false;
}
}
Thank You,
Jason
On Fri, Apr 24, 2009 at 12:03 PM, robotissues <[email protected]> wrote:
> I am stuck. My main activity creates and starts a SurfaceView. My
> app needs to access a listview via the options menu to change
> properties of the items shown in the view.
>
> Two strange things occur:
>
> 1.) When I scroll the listview quickly, the list sometimes gets
> farklempt. Words overlap each other.
>
> 2.) When I select the item and the app returns to the main activity,
> the thread is no longer alive.
>
> If someone out there can offer help I will post the code. This will
> take a little effort. My code is loosely based upon LunarLander and
> the GLSurfaceView examples. If there is a good example (more recent
> example) someone can point me to, that would be boss.
>
> Thank You
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en
-~----------~----~----~----~------~----~------~--~---