I am running a thread in background contains timer and I display this timer in TextView
but when I change current fragment and I return the timer still running in logcat
but does not update in UI
My code:
final Runnable r = new Runnable() {
public void run() {
if (mBound) {
long elapsedTime = stopWatchService.getElapsedTime();
formattedTime = DateUtils.formatElapsedTime(elapsedTime);
Log.i(TAG, "formattedTime " formattedTime);
textView.setText(formattedTime);
}
}
};
Task task = new Task(r);
task.execute((Void) null);
My task:
public class Task extends AsyncTask<Void, Void, Void> {
private static final String TAG = "Task";
private boolean mPaused;
private Runnable mRunnable;
public Task(Runnable runnable, TextView textView) {
mRunnable = runnable;
play();
}
@Override
protected Void doInBackground(Void... params) {
while (!isCancelled()) {
if (!mPaused) {
mRunnable.run();
sleep();
}
}
return null;
}
private void sleep() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.w(TAG, e.getMessage());
}
}
public void play() {
mPaused = false;
}
public void pause() {
mPaused = true;
}
public void stop() {
pause();
cancel(true);
}
public boolean isPaused() {
return mPaused;
}
}
My service:
public class StopWatchService extends Service {
private String TAG = "walkingApp";
StopWatch stopWatch = new StopWatch();
public StopWatchService() {
}
public class LocalBinder extends Binder {
public StopWatchService getService() {
return StopWatchService.this;
}
}
private final IBinder mBinder = new LocalBinder();
public IBinder onBind(Intent intent) {
return mBinder;
}
/*
When the service is started, start stopwatch.
*/
public int onStartCommand(Intent intent, int flags, int startId) {
stopWatch.start();
return START_STICKY;
}
/* return how much time has passed in seconds */
public long getElapsedTime() {
return stopWatch.getElapsedTime();
}
@Override
public boolean stopService(Intent name) {
stopWatch.stop();
return super.stopService(name);
}
@Override
public void onDestroy() {
super.onDestroy();
// stopWatch.stop();
}
}
CodePudding user response:
AsyncTask was deprecated a few years ago, which was, IMHO, long overdue. It had lots of problems, like the one you are encountering, and only really ever worked well in some very special cases.
There are several other ways to handle this situation, including, but not limited to RxJs, executors, and Kotlin Coroutines.
Have a look at The AsyncTask API is deprecated in Android 11. What are the alternatives?
CodePudding user response:
The short answer here is probably that you use a Chronometer
instead of a TextView
. Then all you need to do is set the start time once, and the you no longer need to worry about keeping track of what time to display yourself. You can get rid of your timer. For example (very naive approach):
public class MyActivityOrFragment ... {
//Start time as "uptime"
private static final AtomicLong base =
new AtomicLong(SystemClock.uptimeMillis());
@Override
public void onStart() {
//...
chronometer.setBase(base.get());
}
}
If you want to change this base time whilst the Activity/Fragment is open, then you can get do it in plenty of ways. You could send an intent with the base time as an extra, use an interface, an event bus, monitor a database, etc.