如果用户不使用应用程序,则终止Android计时器(防止在后台运行)

时间:2017-10-24 14:41:33

标签: java android concurrency android-animation

我的应用中有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,此代码也会运行。如果事实它在后台运行,它似乎使用了大量的内存。

我需要运行此代码ONLY if user in the app。事实上,当用户点击Back Button时,此Timer结束,如果用户点击Home Button,过了一段时间该用户不使用该应用,则终止此Timer }。

我需要的是防止使用内存。因为我意识到这段代码运行了一段时间,App冻结了!我需要一个正常的行为。

3 个答案:

答案 0 :(得分:0)

你可以在onBackPressed()onDestroy()中这样做,无论你喜欢什么。

if (t != null) {
   t.cancel();
}

如果需要,您可以在onResume()启动计时器并在onStop()取消计时器,这完全取决于您的要求。

  

如果调用者想要终止计时器的任务执行线程   很快,调用者应该调用计时器的取消方法。 - Android Timer documentation

您还应该看到purgeHow to stop the Timer in android?

答案 1 :(得分:0)

免责声明:这可能不是百分之百的最佳方式,有些人可能认为这是不好的做法。

我在生产应用中使用了以下代码,但它确实有效。然而,我已经将它编辑(删除了应用程序特定的引用和代码)到基本样本中,这应该会给你一个很好的开始。

可以在应用中的任何位置(通过您的mIsAppVisible类)调用静态App变量,以检查代码是否应根据应用需要关注/可见的条件运行。< / p>

您还可以检查扩展mIsAppInBackground的活动中的ParentActivity,看看该应用是否真的具有互动性等。

public class App extends Application {
    public static boolean mIsAppVisible = false;


    ...
}

创建一个“父”活动类,其他所有活动都会延伸。

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;
    }
}

对于您的使用,您可能希望在活动中创建一个方法(代码段假定为MainActivity),该方法处理动画以调用penguin建议的t.cancel();方法。然后,您可以在ParentActivity.applicationDidEnterBackground()方法中添加以下内容:

if (this instanceof MainActivity) {
    ((MainActivity) this).cancelTimer();
}

或者您可以将计时器添加到ParentActivity课程,然后不需要instanceof检查或额外的方法。

答案 2 :(得分:0)

如果ActivityBackStack中的最后一个元素,那么它将被置于后台,就像您按下主页按钮一样。

因此,触发了onPause()方法。

您可以在那里取消动画。

@Override protected void onPause() {
    this.timer.cancel();
}

您还应该使用onResume()方法启动动画。 请注意,onResume()之后也会调用onCreate();所以它甚至适合从冷应用程序启动开始动画。

@Override protected void onResume() {
    this.timer.scheduleAtFixedRate(...);
}
如果您从应用中启动另一个应用程序(例如:铃声选择器),也会调用

onPause()。同样,当您返回应用时,系统会触发onResume()

无需在onBackPressed()中添加相同的代码行。

另外,在onStop()onDestroy()停止动画的重点是什么?

已在onPause()中执行此操作。当你的应用程序进入后台时,动画将被取消并且不会使用尽可能多的内存

不知道为什么我会看到如此复杂的答案。