如果用户不使用应用程序,则终止 Android 计时器(防止 运行 在后台运行)
Terminating Android Timer if user doesn't use the App(Prevent running in the background)
我的应用程序中有一个 Timer
,无限 运行 是一个 Animation
。像这样:
Timer t = new Timer();
t.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
//Running Animation Code
}
});
}
}, 1000, 1000);
现在我意识到,即使用户单击 android 的 Back Button
,这段代码 运行s 也是如此。事实上,它 运行 在后台运行,而且似乎占用了大量内存。
我需要这个代码 运行 ONLY if user in the app
。事实上,当用户点击 Back Button
时,这个 Timer
就会结束,如果用户点击 Home Button
,一段时间后该用户不再使用应用程序,就会终止这个 Timer
.
我需要的是防止使用内存。因为我意识到如果这段代码 运行 一会儿,应用程序就会冻结!我需要一个正常的行为。
你可以这样做,在onBackPressed()
或onDestroy()
,任何适合你的。
if (t != null) {
t.cancel();
}
如果你需要,你可以在onResume()
开始计时,在onStop()
取消计时,这完全取决于你的要求。
If a caller wants to terminate a timer's task execution thread
rapidly, the caller should invoke the timer's cancel method. - Android Timer documentation
您还应该看到 purge 和
How to stop the Timer in android?
免责声明:这可能不是 100% 最好的方法,有些人可能认为这是不好的做法。
我在生产应用程序中使用了以下代码并且它有效。不过,我已将其编辑(删除了特定于应用程序的参考和代码)为一个基本示例,这应该会给您一个很好的开始。
静态 mIsAppVisible
变量可以在您的应用中的任何地方调用(通过您的 App
class),以检查代码是否应该 运行 基于以下条件应用程序需要在 focus/visible.
您还可以在扩展 ParentActivity
的活动中检查 mIsAppInBackground
以查看该应用程序是否真正具有交互性等。
public class App extends Application {
public static boolean mIsAppVisible = false;
...
}
创建一个 "Parent" activity class,您的所有其他活动都会扩展。
public class ParentActivity extends Activity {
public static boolean mIsBackPressed = false;
public static boolean mIsAppInBackground = false;
private static boolean mIsWindowFocused = false;
public boolean mFailed = false;
private boolean mWasScreenOn = true;
@Override
protected void onStart() {
applicationWillEnterForeground();
super.onStart();
}
@Override
protected void onStop() {
super.onStop();
applicationDidEnterBackground();
}
@Override
public void finish() {
super.finish();
// If something calls "finish()" it needs to behave similarly to
// pressing the back button to "close" an activity.
mIsBackPressed = true;
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
mIsWindowFocused = hasFocus;
if (mIsBackPressed && !hasFocus) {
mIsBackPressed = false;
mIsWindowFocused = true;
}
if (!mIsWindowFocused && mFailed)
applicationDidEnterBackground();
if (isScreenOn() && App.mIsAppVisible && hasFocus) {
// App is back in focus. Do something here...
// this can occur when the notification shade is
// pulled down and hidden again, for example.
}
super.onWindowFocusChanged(hasFocus);
}
@Override
public void onResume() {
super.onResume();
if (!mWasScreenOn && mIsWindowFocused)
onWindowFocusChanged(true);
}
@Override
public void onBackPressed() {
// this is for any "sub" activities that you might have
if (!(this instanceof MainActivity))
mIsBackPressed = true;
if (isTaskRoot()) {
// If we are "closing" the app
App.mIsAppVisible = false;
super.onBackPressed();
} else
super.onBackPressed();
}
private void applicationWillEnterForeground() {
if (mIsAppInBackground) {
mIsAppInBackground = false;
App.mIsAppVisible = true;
// App is back in foreground. Do something here...
// this happens when the app was backgrounded and is
// now returning
} else
mFailed = false;
}
private void applicationDidEnterBackground() {
if (!mIsWindowFocused || !isScreenOn()) {
mIsAppInBackground = true;
App.mIsAppVisible = false;
mFailed = false;
// App is not in focus. Do something here...
} else if (!mFailed)
mFailed = true;
}
private boolean isScreenOn() {
boolean screenState = false;
try {
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
screenState = powerManager.isInteractive();
} catch (Exception e) {
Log.e(TAG, "isScreenOn", e);
}
mWasScreenOn = screenState;
return screenState;
}
}
为了您的使用,您可能希望在 activity(代码片段假定 MainActivity
)中创建一个方法来处理动画以调用 t.cancel();
方法 建议。然后,您可以在 ParentActivity.applicationDidEnterBackground()
方法中添加以下内容:
if (this instanceof MainActivity) {
((MainActivity) this).cancelTimer();
}
或者您可以将计时器添加到 ParentActivity
class 然后不需要 instanceof
检查或额外的方法。
如果您的 Activity
是 BackStack
中的最后一个元素,那么它将置于背景中,就像您按下 Home 按钮一样。
因此,onPause()
方法被触发。
因此您可以在那里取消动画。
@Override protected void onPause() {
this.timer.cancel();
}
您还应该在 onResume()
方法中启动动画。
请注意 onResume()
也在 onCreate()
之后调用;所以它甚至适合从应用程序冷启动开始动画。
@Override protected void onResume() {
this.timer.scheduleAtFixedRate(...);
}
如果您从您的应用程序启动另一个应用程序(例如:铃声选择器),也会调用 onPause()
。同样,当您返回您的应用程序时,将触发 onResume()
。
不需要在onBackPressed()
.
中添加相同的代码行
此外,在 onStop()
或 onDestroy()
中停止动画有什么意义?
已经在 onPause()
中完成了。当您的应用程序进入后台时,动画将被取消并且不会使用那么多内存。
不知道为什么我看到这么复杂的答案。
我的应用程序中有一个 Timer
,无限 运行 是一个 Animation
。像这样:
Timer t = new Timer();
t.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
//Running Animation Code
}
});
}
}, 1000, 1000);
现在我意识到,即使用户单击 android 的 Back Button
,这段代码 运行s 也是如此。事实上,它 运行 在后台运行,而且似乎占用了大量内存。
我需要这个代码 运行 ONLY if user in the app
。事实上,当用户点击 Back Button
时,这个 Timer
就会结束,如果用户点击 Home Button
,一段时间后该用户不再使用应用程序,就会终止这个 Timer
.
我需要的是防止使用内存。因为我意识到如果这段代码 运行 一会儿,应用程序就会冻结!我需要一个正常的行为。
你可以这样做,在onBackPressed()
或onDestroy()
,任何适合你的。
if (t != null) {
t.cancel();
}
如果你需要,你可以在onResume()
开始计时,在onStop()
取消计时,这完全取决于你的要求。
If a caller wants to terminate a timer's task execution thread rapidly, the caller should invoke the timer's cancel method. - Android Timer documentation
您还应该看到 purge 和 How to stop the Timer in android?
免责声明:这可能不是 100% 最好的方法,有些人可能认为这是不好的做法。
我在生产应用程序中使用了以下代码并且它有效。不过,我已将其编辑(删除了特定于应用程序的参考和代码)为一个基本示例,这应该会给您一个很好的开始。
静态 mIsAppVisible
变量可以在您的应用中的任何地方调用(通过您的 App
class),以检查代码是否应该 运行 基于以下条件应用程序需要在 focus/visible.
您还可以在扩展 ParentActivity
的活动中检查 mIsAppInBackground
以查看该应用程序是否真正具有交互性等。
public class App extends Application {
public static boolean mIsAppVisible = false;
...
}
创建一个 "Parent" activity class,您的所有其他活动都会扩展。
public class ParentActivity extends Activity {
public static boolean mIsBackPressed = false;
public static boolean mIsAppInBackground = false;
private static boolean mIsWindowFocused = false;
public boolean mFailed = false;
private boolean mWasScreenOn = true;
@Override
protected void onStart() {
applicationWillEnterForeground();
super.onStart();
}
@Override
protected void onStop() {
super.onStop();
applicationDidEnterBackground();
}
@Override
public void finish() {
super.finish();
// If something calls "finish()" it needs to behave similarly to
// pressing the back button to "close" an activity.
mIsBackPressed = true;
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
mIsWindowFocused = hasFocus;
if (mIsBackPressed && !hasFocus) {
mIsBackPressed = false;
mIsWindowFocused = true;
}
if (!mIsWindowFocused && mFailed)
applicationDidEnterBackground();
if (isScreenOn() && App.mIsAppVisible && hasFocus) {
// App is back in focus. Do something here...
// this can occur when the notification shade is
// pulled down and hidden again, for example.
}
super.onWindowFocusChanged(hasFocus);
}
@Override
public void onResume() {
super.onResume();
if (!mWasScreenOn && mIsWindowFocused)
onWindowFocusChanged(true);
}
@Override
public void onBackPressed() {
// this is for any "sub" activities that you might have
if (!(this instanceof MainActivity))
mIsBackPressed = true;
if (isTaskRoot()) {
// If we are "closing" the app
App.mIsAppVisible = false;
super.onBackPressed();
} else
super.onBackPressed();
}
private void applicationWillEnterForeground() {
if (mIsAppInBackground) {
mIsAppInBackground = false;
App.mIsAppVisible = true;
// App is back in foreground. Do something here...
// this happens when the app was backgrounded and is
// now returning
} else
mFailed = false;
}
private void applicationDidEnterBackground() {
if (!mIsWindowFocused || !isScreenOn()) {
mIsAppInBackground = true;
App.mIsAppVisible = false;
mFailed = false;
// App is not in focus. Do something here...
} else if (!mFailed)
mFailed = true;
}
private boolean isScreenOn() {
boolean screenState = false;
try {
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
screenState = powerManager.isInteractive();
} catch (Exception e) {
Log.e(TAG, "isScreenOn", e);
}
mWasScreenOn = screenState;
return screenState;
}
}
为了您的使用,您可能希望在 activity(代码片段假定 MainActivity
)中创建一个方法来处理动画以调用 t.cancel();
方法 ParentActivity.applicationDidEnterBackground()
方法中添加以下内容:
if (this instanceof MainActivity) {
((MainActivity) this).cancelTimer();
}
或者您可以将计时器添加到 ParentActivity
class 然后不需要 instanceof
检查或额外的方法。
如果您的 Activity
是 BackStack
中的最后一个元素,那么它将置于背景中,就像您按下 Home 按钮一样。
因此,onPause()
方法被触发。
因此您可以在那里取消动画。
@Override protected void onPause() {
this.timer.cancel();
}
您还应该在 onResume()
方法中启动动画。
请注意 onResume()
也在 onCreate()
之后调用;所以它甚至适合从应用程序冷启动开始动画。
@Override protected void onResume() {
this.timer.scheduleAtFixedRate(...);
}
如果您从您的应用程序启动另一个应用程序(例如:铃声选择器),也会调用 onPause()
。同样,当您返回您的应用程序时,将触发 onResume()
。
不需要在onBackPressed()
.
此外,在 onStop()
或 onDestroy()
中停止动画有什么意义?
已经在 onPause()
中完成了。当您的应用程序进入后台时,动画将被取消并且不会使用那么多内存。
不知道为什么我看到这么复杂的答案。