应用关闭时的CountDownTimer问题

问题描述 投票:0回答:2

我制作了一个 CountDownTimer 代码,我希望 CountDownTimer 在完成后重新启动,即使应用程序已关闭,但它只会在应用程序正在运行或应用程序重新启动时重新启动。因此,如果我在倒计时为 00:10(分钟:秒)时关闭应用程序并在 30 秒后重新打开应用程序,则计数器应为 00:40,但它从 1 分钟开始......但是如果我关闭应用程序00:40 并在 10 秒后重新打开它,它从 00:30 开始所以很好,但问题是当应用程序关闭并重新打开时它从 1 分钟重新启动....有人可以帮我吗?

我的代码:

package com.example.countdown_implement;

import android.content.SharedPreferences;
import android.os.CountDownTimer;
import android.os.Bundle;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

import java.util.Locale;

public class MainActivity extends AppCompatActivity {
    private static final long START_TIME_IN_MILLIS = 60000;
    private TextView mTextViewCountDown;
    private CountDownTimer mCountDownTimer;
    private boolean mTimerRunning;
    private long mTimeLeftInMillis;
    private long mEndTime;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mTextViewCountDown = findViewById(R.id.text_view_countdown);

}

private void startTimer() {
    mEndTime = System.currentTimeMillis() + mTimeLeftInMillis;

    mCountDownTimer = new CountDownTimer(mTimeLeftInMillis, 1000) {
        @Override
        public void onTick(long millisUntilFinished) {
            mTimeLeftInMillis = millisUntilFinished;
            updateCountDownText();
        }

        @Override
        public void onFinish() {
            //mTimerRunning = false;
            //updateButtons();

            updateCountDownText();
            resetTimer();
            startTimer();

        }
    }.start();

    //mTimerRunning = true;

}


private void resetTimer() {
    mTimeLeftInMillis = START_TIME_IN_MILLIS;
    updateCountDownText();

}

private void updateCountDownText() {
    int minutes = (int) (mTimeLeftInMillis / 1000) / 60;
    int seconds = (int) (mTimeLeftInMillis / 1000) % 60;

    String timeLeftFormatted = String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds);

    mTextViewCountDown.setText(timeLeftFormatted);
}


@Override
protected void onStop() {
    super.onStop();

    SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
    SharedPreferences.Editor editor = prefs.edit();

    editor.putLong("millisLeft", mTimeLeftInMillis);
    editor.putBoolean("timerRunning", mTimerRunning);
    editor.putLong("endTime", mEndTime);

    editor.apply();

}

@Override
protected void onStart() {
    super.onStart();

    SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);

    mTimeLeftInMillis = prefs.getLong("millisLeft", START_TIME_IN_MILLIS);
    mTimerRunning = prefs.getBoolean("timerRunning", false);
    mEndTime = prefs.getLong("endTime", 0);
    mTimeLeftInMillis = mEndTime - System.currentTimeMillis();

    updateCountDownText();
    startTimer();
    if (mTimeLeftInMillis < 0) {
        updateCountDownText();
        startTimer();
    }
  }
}
java android countdowntimer
2个回答
1
投票

已更新

以下是您的代码转换为 CountdownTimer 的代码片段,即使在应用程序关闭、推送到后台或重新启动时,它也会继续工作。

设置

START_TIME_IN_MILLIS
为定时器开始时间,在下面的例子中设置为15秒。

import android.content.SharedPreferences;
import android.os.CountDownTimer;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

import java.util.Locale;

public class MainActivity2 extends AppCompatActivity {
    private static final long START_TIME_IN_MILLIS = 15000;
    private TextView mTextViewCountDown;
    private CountDownTimer mCountDownTimer;
    private boolean mTimerRunning;
    private long mTimeLeftInMillis;
    private long mEndTime;
    private long remainingTimeInMillis;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_new);

        mTextViewCountDown = findViewById(R.id.tv);
    }

    private void startTimer() {
        mCountDownTimer = new CountDownTimer(remainingTimeInMillis, 1000) {
            @Override
            public void onTick(long millisUntilFinished) {
                remainingTimeInMillis = millisUntilFinished;
                mTimeLeftInMillis = millisUntilFinished;
                updateCountDownText();
            }

            @Override
            public void onFinish() {
                //mTimerRunning = false;
                //updateButtons();

                updateCountDownText();
                resetTimer();
                startTimer();

            }
        }.start();

        //mTimerRunning = true;

    }


    private void resetTimer() {
        remainingTimeInMillis = START_TIME_IN_MILLIS;
        updateCountDownText();

    }

    private void updateCountDownText() {


        int minutes = (int) (remainingTimeInMillis / 1000) / 60;
        int seconds = (int) (remainingTimeInMillis / 1000) % 60;

        String timeLeftFormatted = String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds);

        mTextViewCountDown.setText(timeLeftFormatted);
    }


    @Override
    protected void onStop() {
        super.onStop();

        SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
        SharedPreferences.Editor editor = prefs.edit();

        editor.putLong("millisLeft", mTimeLeftInMillis);
        editor.putBoolean("timerRunning", mTimerRunning);
        editor.putLong("endTime", System.currentTimeMillis());
        editor.apply();

    }

    @Override
    protected void onStart() {
        super.onStart();

        SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);

        mTimeLeftInMillis = prefs.getLong("millisLeft", START_TIME_IN_MILLIS);
        mTimerRunning = prefs.getBoolean("timerRunning", false);
        mEndTime = prefs.getLong("endTime", 0);
        if (mEndTime == 0L) {
            remainingTimeInMillis = (mTimeLeftInMillis);
        } else {
            Long timeDiff = (mEndTime - System.currentTimeMillis());
            //to convert into positive number
            timeDiff = Math.abs(timeDiff);

            long timeDiffInSeconds = (timeDiff / 1000) % 60;
           long timeDiffInMillis = timeDiffInSeconds * 1000;
            Long timeDiffInMillisPlusTimerRemaining = remainingTimeInMillis = mTimeLeftInMillis - timeDiffInMillis;

            if (timeDiffInMillisPlusTimerRemaining < 0) {
                timeDiffInMillisPlusTimerRemaining = Math.abs(timeDiffInMillisPlusTimerRemaining);
                remainingTimeInMillis = START_TIME_IN_MILLIS - timeDiffInMillisPlusTimerRemaining;
            }
        }
        updateCountDownText();
        startTimer();
    }
}

0
投票

首先,看这里:了解Activity生命周期

您需要

onResume
onPause
onDestroy
,以便涵盖所有场景。

对于

onResume
,原因是,当你把你的应用程序放到
background
,并通过让它到
foreground
恢复应用程序时,可以进一步应用操作,例如从SharedPreferences中获取最后保存的状态以确保条件被执行。

对于

onPause
,这是至关重要的,因为当你点击你的手机主页按钮时,这个状态将被执行。因此,它确保在销毁之前保存所有状态(保险)。

对于

onDestroy
,这是最关键的部分,因为对于一些低端手机,资源有限,操作系统会通过杀死应用程序来“清理”,所以对于你的应用程序,它会被杀死,所以在它之前被杀了,就可以救国了

因此,每当您启动或使用您的应用程序时,请查询

SharedPreferences
,并进行一些计算以确保一切正确。

使用

service
broadcast
,让您的程序在后台运行。

文档中的一些详细解释:

  1. onResume()

当activity进入Resumed状态后,来到前台,然后系统调用onResume()回调。这是应用程序与用户交互的状态。该应用程序会一直保持这种状态,直到发生某些事情使焦点从该应用程序上移开。例如,此类事件可能是接到电话、用户导航到另一个活动或设备屏幕关闭。

当活动进入恢复状态时,任何与活动生命周期相关的生命周期感知组件都将收到

ON_RESUME
事件。这是生命周期组件可以启用任何需要在组件可见并在前台运行的功能的地方,例如启动相机预览。

当中断事件发生时,Activity进入Paused状态,系统调用

onPause()
回调。

如果Activity从Paused状态回到Resumed状态,系统会再次调用

onResume()
方法。出于这个原因,您应该实施
onResume()
来初始化您在
onPause()
期间释放的组件,并执行每次活动进入 Resumed 状态时必须发生的任何其他初始化。

  1. onPause

系统调用此方法作为用户离开您的活动的第一个指示(尽管这并不总是意味着活动正在被销毁);它表示该活动不再位于前台(尽管如果用户处于多窗口模式,它可能仍然可见)。使用 onPause() 方法暂停或调整在 Activity 处于暂停状态时不应继续(或应适度继续)并且您希望很快恢复的操作。一个活动可能进入这个状态有几个原因。

  1. onDestroy()

onDestroy()
在活动被销毁之前被调用。系统调用此回调是因为:

  1. 活动即将结束(由于用户完全关闭了 活动或由于 finish() 在活动上被调用),或
  2. 系统暂时销毁活动由于 配置更改(例如设备旋转或多窗口模式)

当活动进入销毁状态时,任何与活动生命周期相关的生命周期感知组件都将收到 ON_DESTROY 事件。这是生命周期组件可以在 Activity 被销毁之前清理它需要的任何东西的地方。

在这里看看:后台执行限制

© www.soinside.com 2019 - 2024. All rights reserved.