This is the main Activity of my app. The one holding a CupView. package my.package;
import my.package.CupView.CupThread; import org.openintents.hardware.SensorManagerSimulator; import org.openintents.provider.Hardware; import android.app.Activity; import android.content.Intent; import android.hardware.SensorListener; import android.hardware.SensorManager; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.TextView; public class MyActivity extends Activity { private static final int MENU_NEWGAME = 1; private static final int MENU_RESUMEGAME = 2; private static final int MENU_EXITGAME = 3; private static final int ROLL_DICE_ACTIVITY = 1; /** The modes the game can be in **/ private static final int ENTER = 1; // just entered the game private static final int IN_PROGRESS = 2; // less than 13 turns private static final int GAME_OVER = 3; // 13 turns has been reached private int mMode; private int mTurnCount; private int mHeldDiceCount; private String mName; private CupView mCupView; private Button mScoreButton; private Button mRollButton; private int mRollCount; public static ScoresDbAdapter mDbHelper; private CupThread mCupThread; private long mGameID; TextView mInstruct; private SensorManager mSensorManager; private float mLastX; private SensorListener mAccellListener; private int mShake; private boolean mShaking; /** Called when the activity is first created. */ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // set the content view to the main game board (the cup) setContentView(R.layout.board); if (savedInstanceState == null){ setState(ENTER); mHeldDiceCount = 0; mRollCount = 0; }else{ setState(IN_PROGRESS); } mInstruct = (TextView) findViewById(R.id.top_text); //get the cup view mCupView = (CupView) findViewById(R.id.cup); mCupThread = mCupView.getThread(); // Before calling any of the Simulator data, // the Content resolver has to be set !! Hardware.mContentResolver = getContentResolver(); // Link sensor manager to OpenIntents Sensor simulator mSensorManager = (SensorManager) new SensorManagerSimulator((SensorManager) getSystemService(SENSOR_SERVICE)); //setUpAccell(); // give the LunarView a handle to the TextView used for messages mCupView.setTextView((TextView) findViewById(R.id.text)); // get the score sheet button and set its listener mScoreButton = (Button) findViewById(R.id.score_button); mScoreButton.setOnClickListener(new Button.OnClickListener() { public void onClick(View v){ openScoreSheet(); } }); mRollButton = (Button) findViewById(R.id.roll_button); mRollButton.setOnClickListener(new Button.OnClickListener() { public void onClick(View v){ rollDice(); } }); mDbHelper = new ScoresDbAdapter(this); mDbHelper.open(); } //------------------------------------------------------------------------- private void openScoreSheet(){ if (mMode==IN_PROGRESS){ Intent i = new Intent(this, ScoreSheet.class); i.putExtra("my.package.GameID", mGameID); startActivity(i); } } //------------------------------------------------------------------------- public boolean onCreateOptionsMenu(Menu menu){ super.onCreateOptionsMenu(menu); menu.add(0,MENU_NEWGAME,0,R.string.menu_newgame); menu.add(0,MENU_RESUMEGAME,0,R.string.menu_resumegame); menu.add(0,MENU_EXITGAME,0,R.string.menu_exitgame); return true; } //------------------------------------------------------------------------- public boolean onOptionsItemSelected(MenuItem item){ switch (item.getItemId()){ case MENU_NEWGAME: createNewGame(); return true; case MENU_RESUMEGAME: resumeGame(); return true; case MENU_EXITGAME: return true; } return false; } //------------------------------------------------------------------------- /** * My own listener interface to use for getting values back from a dialog. */ public interface CreateGameListener{ public void onOKClick(String name); public void onCancelClick(); } //------------------------------------------------------------------------- /** * Method called from CreateGameListener's onOKClick */ public void okClick(String n, long game){ mName = n; // TextView topText = (TextView) findViewById(R.id.top_text); // Long gameInt = new Long(game); // topText.setText(gameInt.toString()); mGameID = mDbHelper.createGame(n); } //------------------------------------------------------------------------- private void createNewGame(){ mRollCount = 0; mTurnCount = 0; setState(IN_PROGRESS); // start the activity that asks for the name of the new game CreateGameListener listener = new CreateGameListener(){ public void onOKClick(String n){ okClick(n,mGameID); } public void onCancelClick(){ } }; CreateGame dialog = new CreateGame(mCupView.getContext (),listener); dialog.show(); } //------------------------------------------------------------------------- private void resumeGame(){ setState(IN_PROGRESS); // create a new intent that has a list of all the games Intent i = new Intent(this,ResumeGameList.class); startActivity(i); } //------------------------------------------------------------------------- private void rollDice(){ if (mMode==IN_PROGRESS){ // create a new intent for the roll dice view Intent i = new Intent(this,RollDice.class); mRollCount = mRollCount + 1; if (mRollCount == 3){ mTurnCount += 1; } if (mTurnCount == 13){ setState(GAME_OVER); } i.putExtra("my.package.RollCount", mRollCount); i.putExtra("my.package.GameID",mGameID); startActivityForResult(i,ROLL_DICE_ACTIVITY); // startActivity(i); // finish(); } } //------------------------------------------------------------------------- @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 1){ // if its returning after the third role if (resultCode == RollDice.READY_TO_SCORE){ // start the ChooseScore Activity. mRollCount = 0; startActivity(data); }else{ mHeldDiceCount = resultCode; } } } //------------------------------------------------------------------------- public void setState(int mode){ if (mode == ENTER){ //mInstruct.setText("Press Menu to start a game."); } if (mode == IN_PROGRESS){ //mInstruct.setText("Shake phone to shake dice."); } if (mode == GAME_OVER){ //mInstruct.setText("Game Over"); } mMode = mode; } //------------------------------------------------------------------------- public int getState(){return mMode;} //------------------------------------------------------------------------- protected void onPause(){ super.onPause(); } // //------------------------------------------------------------------------- protected void onResume(){ super.onResume(); } //------------------------------------------------------------------------- public void setUpAccell(){ mLastX = 0; mShake = 0; mAccellListener = new SensorListener() { Float x; public void onSensorChanged(int sensor, float[] values){ if (sensor == SensorManager.SENSOR_ACCELEROMETER){ x = values[SensorManager.DATA_X]; if ((x-mLastX>.5)||(x-mLastX<-.5)){ mShake += 1; } // if (((x-mLastX<.5)||(x-mLastX>-.5))&&(mShake>=0)){ // mShake -= 1; // } if (mShake>3){ mShaking = true; mCupThread.setState(mCupThread.STATE_SHAKING); } if (mShake==0&&mShaking){ mShaking = false; mCupThread.setState(mCupThread.STATE_RUNNING); } mLastX = x; } } public void onAccuracyChanged(int sensor, int acc){} }; // now connect to simulator SensorManagerSimulator.connectSimulator(); // now enable the new sensors mSensorManager.registerListener(mAccellListener, SensorManager.SENSOR_ACCELEROMETER); } } On Mar 31, 10:35 pm, kbeal10 <kbea...@gmail.com> wrote: > This is where the thread variable is declared. > > private Context mContext; > /** The thread that actually draws teh animations. */ > private CupThread thread; > private TextView mStatusText; > > public CupView(Context context, AttributeSet attrs){ > super(context,attrs); > > //register our interest in hearing about changes to our > surface > SurfaceHolder holder = getHolder(); > holder.addCallback(this); > mContext = context; > setFocusable(true); > // create thread only; it's started in surfaceCreated() > } > > I'm sorry for the confusion about "exiting" in rollDice(). Indeed, I > am not exiting here, but starting another Activity. > > I believe, as you mentioned, this is a case where the original > activity is still there, and then being re-displayed. However, > CupView's surfaceDestroyed() is called when I start the other Activity > in rollDice(). This means that when the Activity holding CupView > resumes I should be able to create a new thread and start it. I am > aware you can't call start() on the same thread twice, but since > surfaceDestroyed() is called that thread is terminated with the .join > () call. A new thread is then created and started in surfaceCreated(). > > I will post the full code to both the Activity holding the CupView, as > well as the CupView in the following post. > > On Mar 31, 10:17 pm, Dianne Hackborn <hack...@android.com> wrote: > > > I don't think you've included enough code. Where is this 'thread' variable > > defined? Where do you clear it after finishing the thread? > > > I am also confused by the comment saying you "exiting" the activity in > > rollDice -- you aren't calling finish, you are just starting another > > activity, so the original activity is still there, and its window will just > > be re-displayed when it is shown again. > > > The only thing I can think of is that you aren't handling the case where > > your window is hidden and then shown again, causing surfaceCreated to be > > called a second time on the same SurfaceView, but again there isn't enough > > code here to really tell what is happening. > > > Also you do know that you can only call Thread.start() once on a particular > > thread object, right? > > >http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Thread.html#start() > > > On Tue, Mar 31, 2009 at 6:46 PM, kbeal10 <kbea...@gmail.com> wrote: > > > > I'm writing a game using two different SurfaceView's (RollView and > > > CupView) in two different activities. Both SurfaceView's heavily > > > resemble the LunarLander demo. > > > > The RollView SurfaceView is working fine. When leaving the Activity, > > > RollView's surfaceDestroyed() is called, killing the thread. If I then > > > re-enter that Activity, the thread is recreated in RollView's > > > constructor and then started in surfaceCreated(). > > > > However in CupView the thread never seems to go away. SurfaceDestroyed > > > is being called, but upon reentering the Activity I get the following > > > error: > > > > java.lang.IllegalThreadStateException: Thread already started. > > > > This thrown is in surfaceCreated() at the thread.start() call. > > > > The difference between the two, and apparently the problem, is that in > > > the RollView Activity I call finish() when done. When leaving the > > > CupView Activity, I'm doing a startActivityForResult > > > (i,ClassWithRollView.class);......not calling finish(). > > > > This is because after leaving the RollView, I want to return to the > > > CupView. Below is relevant code: > > > > /** This where I'm exiting the Activity with the CupView **/ > > > private void rollDice(){ > > > if (mMode==IN_PROGRESS){ > > > // create a new intent for the roll dice view > > > Intent i = new Intent(this,RollDice.class); > > > mRollCount = mRollCount + 1; > > > if (mRollCount == 3){ > > > mTurnCount += 1; > > > } > > > if (mTurnCount == 13){ > > > setState(GAME_OVER); > > > } > > > i.putExtra("my.package.RollCount", mRollCount); > > > i.putExtra("my.package.GameID",mGameID); > > > startActivityForResult(i,ROLL_DICE_ACTIVITY); > > > } > > > } > > > > /** This is CupView's surfaceCreated/Destroyed **/ > > > > //------------------------------------------------------------------------- > > > -------------------- > > > /* Callback invoked when the Surface has been created and is read > > > 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 > > > Log.d("MyApp","cup view surface created"); > > > thread.setRunning(true); > > > thread.start(); > > > } > > > > //------------------------------------------------------------------------- > > > -------------------- > > > /* 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! > > > * (Unless its REALLY asking for it.) > > > */ > > > 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(wouldn't want that!) after we return and > > > explode > > > (ahhh!). > > > Log.d("MyApp","cup view surface destroyed"); > > > boolean retry = true; > > > thread.setRunning(false); > > > while (retry){ > > > try{ > > > thread.join(); > > > retry = false; > > > }catch(InterruptedException e){ > > > > } > > > } > > > } > > > > So why is the thread saying its already started when surfaceDestroyed > > > () has been called? > > > > A possible workaround is to call finish() on the CupView Activity in > > > the rollDice() method above. This doesn't seem to follow common > > > paradigm though. Any other solutions, comments? All help is > > > appreciated. > > > -- > > Dianne Hackborn > > Android framework engineer > > hack...@android.com > > > Note: please don't send private questions to me, as I don't have time to > > provide private support. All such questions should be posted on public > > forums, where I and others can see and answer them. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Android Developers" group. To post to this group, send email to android-developers@googlegroups.com To unsubscribe from this group, send email to android-developers-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/android-developers?hl=en -~----------~----~----~----~------~----~------~--~---