1

I have tried some ways to do it and didn't secced. I have MainActivity which start 3 thread. I want to stop the threads when the user press "back" bottum or when from some reason the app stop (phone call for example). and after the activity again seen (when the user come back to the app) the thread will continue from where they stop. All the threads defined in MainActivity and there they start. Thanks!

public class MainActivity extends Activity
{

    //threads
    private PingPongGame gameThread;
    private PaddleMover paddleMoverThread;
    private PresentThread giftThread;


    public GameSounds gameSounds;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        super.onCreate(savedInstanceState);


        gameLevel = new GameLevel0(screenWidth , screenHeight, this.giftArr);

        gameLevelView = new GameLevelView(this,gameLevel);

        // Creating the game view
        this.gameView = new PingPongView(this);


        // Setting the gameView as the main view for the PingPong activity.
        setContentView(gameView);


if(gameThread == null){
        //create the main thread
        gameThread = new PingPongGame( gamePaddle, gameView, gameLevel , message , ballArr , gameSounds);

        //create the thread responsible for moving the paddle
        paddleMoverThread = new PaddleMover(gamePaddle, gameView);

        //create the thread responsible for present
        giftThread = new  PresentThread(gamePaddle , gameView , gameLevel, message ,  giftArr , ballArr,gameSounds );

        gameThread.start();
        paddleMoverThread.start();
        giftThread.start();

}
    }

    //This method is automatically called when the user touches the screen
    @Override
    public boolean onTouchEvent(MotionEvent event)
    {
        float destination;
    //  Toast.makeText(this, "try!", Toast.LENGTH_SHORT).show();
        //get the x coordinate of users' press
        destination = event.getX();

        //notify the paddle mover thread regarding the new destination
        gamePaddle.setPaddleDestination(destination);

        return true;
    }
}

Example of one of my threads:

public class PaddleMover extends Thread
{
    private Tray gamePaddle; //holds a reference to the paddle
    private PingPongView gameView; //holds a reference to the main view

    //for stop
    private Object mPauseLock;
    private boolean mPaused;


    //initialize class variables
    public PaddleMover(Tray thePaddle, PingPongView mainView)
    {
        gamePaddle = thePaddle;
        gameView = mainView;

        //for stop and resume threads
        mPauseLock = new Object();
        mPaused = false;
    }

    //main method of the current thread
    @Override
    public void run()
    {
        //infinitely loop, and move the paddle if necessary
        while ((Const.isLose == false) && (Const.isCompleteThisLevel==false) && (Const.isDestroy == false))
        {
            //check whether the paddle should be moved
            if (gamePaddle.getMiddle() != gamePaddle.getPaddleDestination())
            {
                //move the paddle
                gamePaddle.move();

                //send a request to refresh the display
                gameView.postInvalidate();
            }
            try
            {
                PaddleMover.sleep(3);
            }
            catch (InterruptedException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            //for stop and resume
            synchronized (mPauseLock) {
                while (mPaused) {
                    try {
                        mPauseLock.wait();
                    } catch (InterruptedException e) {
                    }
                }
            }

        }
    }
    /**
     * Call this on pause.
     */
    public void onPause() {
        synchronized (mPauseLock) {
            mPaused = true;
        }
    }

    /**
     * Call this on resume.
     */
    public void onResume() {
        synchronized (mPauseLock) {
            mPaused = false;
            mPauseLock.notifyAll();
        }
    }
}
GO VEGAN
  • 1,113
  • 3
  • 15
  • 44
  • Did u checked this ? http://stackoverflow.com/questions/6776327/how-to-pause-resume-thread-in-android – Rahul Aug 28 '13 at 18:22
  • yes. Maybe I do something wrong in the onCreate? I will edit my question with code. – GO VEGAN Aug 28 '13 at 18:40
  • Are you calling `onResume` methods on all threads when your activity pauses?, I don't see that implementation in the code you've posted. If your supporting Back button (popping the activity from the stack) remember that your activity is destroyed, so you would have to save the state of the threads in a database or somewhere else so they can be restored later. – Raúl Juárez Aug 28 '13 at 19:27
  • Yes, I did it in all my 3 thread. What if I don't want to save the state and only start the method run in all of them from start? – GO VEGAN Aug 28 '13 at 19:40
  • Then it's correct as it is, starting them in the `onCreate` method, then what is the problem you have? Threads don't stop? `Exception` is thrown? – Raúl Juárez Aug 28 '13 at 20:25
  • It is still running. (When I run it in my phone I still sound the sounds the thread should do , even when I press the back bottom) – GO VEGAN Aug 28 '13 at 20:41

1 Answers1

0

You can achieve a lot better control with your threads using Runnable objects. Instead of defining your logic using a loop within the run() method, do the following:

  1. Define your framewise logic for each thread within Runnable objects. Override the run() method. Do not use a while loop within your Runnable.

  2. Create a variable which tracks whether or not your game is paused. Use this variable to create a single while() loop within a main thread.

  3. Define a Thread class and get it's Handler. You can do this like so:

    class WorkerThread extends Thread
    {
        private volatile Handler mHandler;
        //volatile so you can try to acquire it until it is instantiated
    
        @Override
        public void run()
        {
            //This is pretty much boilerplate for worker thread implementations
            Looper.prepare();
            //Handlers must be instantiated by their respective threads
            mHandler = new Handler();
            Looper.loop();
        }
    
        @Override
        public Handler getHandler()
        {
            return mHandler;
        }
    }
    
  4. Instantiate multiple WorkerThreads and acquire references to their Handler objects.

  5. In each frame, pass the Runnable() which defines the logic you want the Thread to execute to the Handler using the postRunnable() method.
  6. Use ConditionVariable objects to make sure you don't call the postRunnable() method while the WorkerThread is still executing.

    Runnable thread1runnable = new Runnable()
    {
         @Override
         public void run()
         {
             //Do your logic here
             ...
             thread1finished.open();    //This lets the block() function return
         }
     }
    
    ConditionVariable thread1finished = new ConditionVariable();
    
    thread1finished.open(); //Make sure the loop doesn't block the first time through
    
    Thread thread1 = new WorkerThread();
    //Start the thread to acquire the handler and prepare it for looping
    thread1.start();
    //Call stop() when shutting down your game, not pausing
    
    Handler thread1handler;
    while (thread1handler != null)
         thread1handler = thread1.getHandler();
    //A crude way of making sure you acquire the instantiated handler, you can top this
    
    while (gameRunning)
    {
        if (!isPaused)    //Stops work when your isPaused variable is set
        {
             thread1finished.block();    //Wait for the last runnable to finish
             //Lock the ConditionVariable so the loop will block
             thread1finished.close();
             //Signal the worker thread to start crunching
             thread1handler.postRunnable(thread1runnable);
        }
    }
    
  7. In your onPause() override, set the variable that stops your while() loop from posting the Runnable objects to your WorkerThreads. Enjoy automatic starting and stopping!

There may be issues adapting this method to three different threads which you don't want to synchronize frame-per-frame. Let me know how it goes.

Boston Walker
  • 534
  • 1
  • 6
  • 19