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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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
> > [email protected]
>
> > 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 [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
-~----------~----~----~----~------~----~------~--~---