2

My program should repeat a method until a button is pressed. I tried this, but is doesn't work:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    tts = new TextToSpeech(this, this);
    Button button1 = (Button)findViewById(R.id.button1);
    Button button2 = (Button)findViewById(R.id.button2);
    button1.setOnClickListener(this);
    button2.setOnClickListener(this);
}


public void onClick (View v){
    switch(v.getId()) {
    case R.id.button1: 
        mainprogram();
        break;
    case R.id.button2: 
        perform = false;
        break;
    }
}



public void mainprogram(){

    while(perform == true){
        speak();
        }
    }

(Of course I programmed the "speak()" method)

Could you tell me where the problem is or if there are any methods to solve it?

Sal-laS
  • 11,016
  • 25
  • 99
  • 169
  • once you are inside the method you get outside the while loop. you might wanna put the method code inside the loop and then use `break;` to get outside the loop – SMR Apr 01 '14 at 12:43
  • make the `perform` as `transient`. Due to optimization compiler, while loop is always true.When you make transient, `perform` value will be checked before entering into `while loop`. – Rahul Apr 01 '14 at 12:45

4 Answers4

4

The problem is that your loop runs on the UI thread. I guess the whole UI freezes as you start the loop.

You should run it on a separate thread. Like:

case R.id.button1: 
    Thread th = new Thread(new Runnable(){
       public void run(){
           mainprogram()
       }
    }).start();
    break;

Also, since you modify "perform" from separate threads, you should also make the perform variable volatile, to make the changes visible to other threads, as soon as the modification happens.

You can read more about volatile here: Do you ever use the volatile keyword in Java?

Community
  • 1
  • 1
kupsef
  • 3,357
  • 1
  • 21
  • 31
0

To stop a while loop just use break;

So in your case:

while(perform == true){
    speak();
    if( ... somereason ...) break;
}

Where ... somereason ... should be valid code.

If the method speak() is the one that decides if you need to break, just put the code of speak() directly in the while loop instead of the method call. Or return false from speak and check:if(!speak()) break;

VM4
  • 6,321
  • 5
  • 37
  • 51
  • I know but is there any method for buttons like "waspressed()"? – user3107025 Apr 01 '14 at 12:45
  • I don't understand the question, when you click a button the method onClick() gets executed (assuming you added the listener to the button or an onClick property to xml). – VM4 Apr 01 '14 at 12:54
  • This is not a solution. He already has the perform variable to control the loop, why would he need this?. His problem is that, the loop runs on the UI thread... See my answer. – kupsef Apr 01 '14 at 12:56
  • There is no evidence to support that claim, we don't know what speak() does. – VM4 Apr 01 '14 at 12:57
  • His condition is the perform-flag he uses. The problem is that he cannot change that once he is inside the loop running in the UI-thread. This answer will not solve his problem! – Christian Apr 01 '14 at 12:59
  • I think, This is better to use Threads to reduce the consummation of the phone resources as @kupsef said – Sal-laS Apr 01 '14 at 13:00
0

Since mainprogram will be running on the UI thread, it will block all UI until it breaks from the loop.

Clicking R.id.button2 will not respond (because the UI thread is blocked), so perform will not be set to false.

Perform mainprogram off the main thread, and clicking the button will stop it at some point later

FunkTheMonk
  • 10,908
  • 1
  • 31
  • 37
0

I think the problem is that you are running the while loop in the same thread your listeners and your UI is running in. Thus, as soon as your program enters mainprogram(), it will hang up in this loop, because it can no longer react to your UI (thus, perform will always be true)!

The problem you are facing might be solved with running the content of mainprogram() in another Thread.

Your code might look something like this:

class MainActivity extends Activity
{
    //...
    private static boolean perform;

    private static getPerform()
    {
        return perform;
    }

    public void onClick (View v){
        switch(v.getId()) {
            case R.id.button1:
                perform = true;

                Thread t = new SpeakThread();
                t.start();

                break;

            case R.id.button2:
                perform = false;
                break;
        }
    }
}

class SpeakThread extends Thread
{
    public void run()
    {
        while(MainActivity.getPerform())
        {
            speak();
        }
    }
}
Christian
  • 1,589
  • 1
  • 18
  • 36