屏幕锁定时,计时器停止运行(反应原生)

时间:2017-12-28 09:05:00

标签: javascript react-native

当我锁定屏幕时,我的计时器停止了。到目前为止,该函数看起来像这样:

function startTimer(dispatch, getState, duration, tickDuration = 1000) {
  return new Promise((resolve, reject) => {
    // XXX: Gross local state to keep track of remaining seconds
    let remaining = duration;
    let handle = setInterval(function() {
      const timerState = getState().countdown;
      // Clear either if the timer stopped or if the handle is a different
      // handle (ex. new timer started before this one completed)
      if (!timerState.inProgress || timerState.timerHandle !== handle) {
        clearInterval(handle);
        resolve(false);
      } else {
        remaining--;
        if (remaining === 0) {
          clearInterval(handle);
          resolve(true);
        }

        dispatch({
          type: TIMER_COUNTDOWN_TICK,
        });
      }
    }, tickDuration);

    dispatch({
      type: TIMER_COUNTDOWN_START,
      duration: duration,
      timerHandle: handle,
    });
  });
}

我知道如何更改它,以便当用户锁定屏幕然后又会回来时它会运行吗?

谢谢!

3 个答案:

答案 0 :(得分:2)

您必须在应用程序的后台运行计时器 使用此模块 react-native-background-timer 您的进程正在后台运行。

import BackgroundTimer from 'react-native-background-timer';

答案 1 :(得分:1)

问题是当您离开选项卡时间隔被冻结(例如通过锁定),因此您无法保证setInterval始终需要一秒钟才能运行。您可以使用clocktime来检查:

  const delay = t => new Promise(res => setTimeout(res, t));

  async function timer(duration, tickDuration = 1000){
   const end = +new Date() + duration;
   while(+new Date() < end) await delay(tickDuration);
  }

所以可以做到

 timer(20000).then(console.log)

答案 2 :(得分:1)

我通过比较2个日期对象然后从中获取秒来正确更新我的UI来解决它。建议的react-native-background-timer模块对我来说并不起作用。我的startTimer函数现在看起来像这样:

function startTimer(dispatch, getState, duration, tickDuration = 1000) {
  return new Promise((resolve, reject) => {
    // XXX: Gross local state to keep track of remaining seconds
    let remaining = duration;
    var endTime = new Date();
    endTime.setSeconds(endTime.getSeconds() + remaining);
    let handle = setInterval(function() {
      const timerState = getState().countdown;
      // Clear either if the timer stopped or if the handle is a different
      // handle (ex. new timer started before this one completed)
      if (!timerState.inProgress || timerState.timerHandle !== handle) {
        clearInterval(handle);
        resolve(false);
      } else {
        var compareTime = new Date();
        if (compareTime > endTime) {
          clearInterval(handle);
          resolve(true);
        }

        dispatch({
          type: TIMER_COUNTDOWN_TICK,
          endTime: endTime,
        });
      }
    }, tickDuration);

    dispatch({
      type: TIMER_COUNTDOWN_START,
      duration: duration,
      timerHandle: handle,
    });
  });
}

然后我也调整了调度功能:

function countdown(state = {
  remaining: 0,
  inProgress: false,
  timerHandle: -1,
}, action) {
  switch (action.type) {
    case TIMER_COUNTDOWN_START:
      return Object.assign({}, state, {
        remaining: action.duration,
        inProgress: true,
        timerHandle: action.timerHandle,
      });
    case TIMER_COUNTDOWN_TICK:
      var endTime = action.endTime;
      var compareTime = new Date();
      var secondsDifference = Math.abs(endTime - compareTime) / 1000;

      return Object.assign({}, state, {
        remaining: secondsDifference,
        inProgress: true,
      });
    case REHYDRATE:
      const incoming = action.payload.countdown;
      if (incoming) {
        return {
          ...state,
          ...incoming,
          remaining: processCountdownRehydration(incoming.remaining),
          inProgress: false,
          timerHandle: -1,
        };
      }
      return state;
    case USER_LOG_OUT:
    case BACK_BUTTON_PRESSED:
      return { ...state, remaining: 0, inProgress: false, timerHandle: -1 };
    default:
      return state;
  }
}