问题
Scenario
I have a runnable that outputs a the value of a variable every 1 second. The runnable starts when I start the mainActivity and runs throughout the app in the background.
Problem
When I close the app (hidden state) and start the app again, the logcat starts outputting faster. It goes faster everytime I do this. Why ?
@Override
public void onStart()
{
mHandler.postDelayed(myRunnable, 1000);
super.onStart();
}
public Runnable myRunnable = new Runnable()
{
@Override
public void run()
{
count ++;
android.util.Log.w(" SYNC ", "COUNT:"+count);
mHandler.postDelayed(myRunnable, 1000);
}
};
SOLUTION / EDIT
Thank you all for answering ! I will give credit. However, it was @pskink who posted this Android Runnable runs faster after Resume , that solved it for me.
回答1:
call removeCallbacksAndMessages(null) before calling postDelayed
回答2:
Because everytime you show app after hiding, onStart method is called, causing new instance of runnable to be created doing the same job.
So to solve this, you need to stop your Runnable in onStop method.
As a general rule of thumb, when overriding lifecycly methods like onCreate
, onStart
, onResume
to trigger some continuous behaviour, you need to disable this behaviour in their respective counterparts (onDestroy
, onStop
, onPause
).
So in your case, one way to disable behaviour triggered in onStart (starting new thread), is to stop this thread in onStop. For example:
public Runnable myRunnable = new Runnable()
{
private boolean stopped = false;
public synchronized void stop() {
stopped = true;
}
public synchronized void reset() {
stopped = false;
}
@Override
public void run()
{
if(stopped) return;
count ++;
android.util.Log.w(" SYNC ", "COUNT:"+count);
mHandler.postDelayed(myRunnable, 1000);
}
};
Now just call myRunnable.stop()
in onStop()
method. If you are reusing myRunnable instance, then call myRunnable.reset()
in onStart()
to enable it again.
回答3:
Maybe this image will help. If you move your code to onCreate it should be OK.

回答4:
You can ask if you already have one runnable at onStart(). I if it is null, you create the new runnable And if it is not null you do nothing
回答5:
try
removeCallbacks(myRunnable)
in onPause() and post the callbacks in onResume()
EDIT (including my comments into the answer):
When you return to the Activity, the Activity is in fact re-created, so you have two Activities: one shown and one invisible. And the runnables still repost themselves, each one having an implicit pointer to the Activity that created it... This is usually called a leak, or an activity leak.
Also please note that code that runs without user interaction should not be placed into an Activity, it should be a Service.
In addition, if counter is not static, you cannot access it after your activity leaves the screen.
From the MVC (Model--View--Controller) viewpoint, Activity=Controller. The View is the view hierarchy specified in the layout XML, we can create our own custom view classes, but usually we reuse the existing ones. And the Model is what must survive after the screen turns by 90 degrees (the Activity and the view hierarchy get re-created when orientation changes). The runnable re-post logic should likely belong to the Model.
来源:https://stackoverflow.com/questions/21131878/android-runnable-runs-faster-after-resume