Question

I want to make stopwatch. And i create stopwatch class like this. And when i call onPause in another Activity its freeze application.

public class StopWatch implements Runnable {
private Object mPauseLock;
private boolean mPaused;
private boolean mFinished;
private ArrayList<TextView> textFields;
private Handler mHandler = new Handler();

public StopWatch( ArrayList<TextView> textFields) {
    mPauseLock = new Object();
    mPaused = false;
    mFinished = false;
    this.textFields =textFields;
}

public void run() {

        textFields.get(1).setText("progressing...");
        if (!mPaused) {
            mHandler.postDelayed(this, 1000);
        }
        synchronized (mPauseLock) {
            while (mPaused) {
                try {
                    mPauseLock.wait();
                } catch (InterruptedException e) {
                }
            }
        }
}

public void onPause() {
    synchronized (mPauseLock) {
        mPaused = true;
    }
}

public void onResume() {
    synchronized (mPauseLock) {
        mPaused = false;
        mPauseLock.notifyAll();
    }
}

}

and i create instance of class in another View like. Can somebody exmplain me where is problem?

stopky = new StopWatch(textFields);
stopky.run();

// do another stuff and register buttons with onClickListener and call
stopky.onPause(); // freeze application
stopky.onResume();
Was it helpful?

Solution

You can't Object.wait() in a run method called from a Handler, which is probably running on the main/UI Thread.

The whole Android app is coordinated via short methods which register with the main/UI Thread. You're probably registering your stopwatch there, too. It's not possible to perform a while loop there and at the same time process events from the user interface..

A quick solution would be to re-schedule your run method and check the status the next time it gets called. Basically like so:

public void run() {
    textFields.get(1).setText("progressing...");
    if (!mPaused) {
        // do what has to be done when stopwatch is running
        mHandler.postDelayed(this, 1000);
    } else {
        // just re-schedule with a shorter delay
        mHandler.postDelayed(this, 10);
    }
}

An even better way would be to go for a fully event-driven design and avoid calling the stopwatch at all while it is stopped. In this case, you would simply re-start it from the Button's event handler.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top