
* 겪고 있는 문제 상황을 최대한 자세하게 작성해주세요.
* 문제 해결을 위해 어떤 시도를 해보았는지 구체적으로 함께 알려주세요.
안녕하세요.
종합반 수강 후 개인 앱을 만들어보고 싶어서 개발 중인데요,
코드를 아무리 봐도 모르겠고... 질문할만한 곳을 찾지 못 해 이곳을 찾아왔습니다...
(강의에서 알려주셨던 커뮤니티는 닫힌 것 같아요ㅜㅜ)
열품타 같은 타이머 어플을 만들고 싶은데요. 실행 조건은 아래와 같습니다.
상태관리를 위해 service 파일을 만들었고, 그 안에서 돌아가는 코드 중 일부이고요.
현재 서버는 구축하지 않아서 Hive 방식으로 로컬에 저장되도록 해둔 상태입니다.
에뮬레이터에서 타이머가 움직이긴 하는데, 타이머를 중지한 후 다시 시작할 때, 저장된 이전 시간에서 정확히 이어지지 않고 잘못된 값으로 시작합니다.
이전 값이 중복으로 더해지는 것 같습니다.
예를 들면,
새로 과목을 추가하여 00:00:00으로 시작.
3초 실행 후 정지하면 00:00:03이 아니라 00:00:06으로 저장됨.
다시 시작버튼을 누르면 00:00:10으로 시작됨.
3초 실행 후 정지하면 00:00:19로 저장됨.
이런식으로 값이 이상하게 저장되고 있는 것으로 보입니다.
타이머 경과 시간은 Hive를 사용해 저장하고 있고,
저장된 이전 시간(`previousElapsedMilliseconds`)을 기반으로 타이머를 이어서 작동시키고자 합니다.
수업 외 내용이지만 의견 주시면 너무 감사드리겠습니다..
구글링도 해보고 GPT 한테도 물어봤는데 도무지 모르겠습니다...ㅜㅜ
답변 어려우실 경우 이런 문제를 물어볼 수 있는 사이트라도 소개 부탁드립니다.🙏
▼만들고자 하는 화면

final Box<Subject> _subjectBox = Hive.box<Subject>('subjects');
final Box<Map> _dailyRecordsBox =
Hive.box<Map>('dailyStudyRecords'); // 날짜별 기록 저장
final Box<int> _elapsedTimesBox = Hive.box<int>('elapsedTimes'); // 타이머 상태 저장
List<Subject> get subjectList => _subjectBox.values.toList();
// 타이머 상태 관리용 변수
final Map<String, Stopwatch> _stopwatches = {}; // 과목별 Stopwatch
final Map<String, Timer> _timers = {}; // 과목별 Timer
final Map<String, DateTime> _currentSessionStartTimes = {}; // 과목별 시작 시간
// 초기 데이터 로드 (Hive에서 불러오기)
void loadSubjectsFromHive() {
if (!_elapsedTimesBox.isOpen) {
print("Error: 'elapsedTimes' Box is not open");
return;
}
for (var subject in subjectList) {
final elapsedMilliseconds =
_elapsedTimesBox.get(subject.id) ?? 0; // null 처리
if (elapsedMilliseconds > 0) {
_stopwatches[subject.id] = Stopwatch(); // Stopwatch 초기화
print(
"Loaded Stopwatch for ${subject.name} with $elapsedMilliseconds ms");
}
}
Future.microtask(() {
notifyListeners();
});
}
void startTimer(String id) {
final subject = _subjectBox.get(id);
if (subject != null) {
if (!_stopwatches.containsKey(id)) {
_stopwatches[id] = Stopwatch(); // Stopwatch 초기화
}
final stopwatch = _stopwatches[id]!;
final previousElapsedMilliseconds = _elapsedTimesBox.get(id) ?? 0;
if (!stopwatch.isRunning) {
stopwatch.start();
// 기존 타이머 취소
_timers[id]?.cancel();
// 새로운 타이머 시작
_timers[id] = Timer.periodic(Duration(seconds: 1), (timer) {
final currentElapsedMilliseconds = stopwatch.elapsedMilliseconds;
final totalElapsedMilliseconds =
previousElapsedMilliseconds + currentElapsedMilliseconds;
final formattedTime =
_formatDuration(Duration(milliseconds: totalElapsedMilliseconds));
updateTimeSpent(id, formattedTime);
_elapsedTimesBox.put(id, totalElapsedMilliseconds);
});
}
}
}
void stopTimer(String id) {
final subject = _subjectBox.get(id);
if (subject != null) {
final stopwatch = _stopwatches[id];
if (stopwatch != null && stopwatch.isRunning) {
stopwatch.stop();
_timers[id]?.cancel();
final currentElapsedMilliseconds = stopwatch.elapsedMilliseconds;
final previousElapsedMilliseconds = _elapsedTimesBox.get(id) ?? 0;
final totalElapsedMilliseconds =
previousElapsedMilliseconds + currentElapsedMilliseconds;
_elapsedTimesBox.put(id, totalElapsedMilliseconds);
final formattedTime =
_formatDuration(Duration(milliseconds: totalElapsedMilliseconds));
updateTimeSpent(id, formattedTime);
}
}
}
String getTotalTimeSpent() {
int totalSeconds = subjectList.fold<int>(0, (sum, subject) {
final parts = subject.timeSpent.split(':').map(int.parse).toList();
return sum + (parts[0] * 3600) + (parts[1] * 60) + parts[2];
});
final hours = totalSeconds ~/ 3600;
final minutes = (totalSeconds % 3600) ~/ 60;
final seconds = totalSeconds % 60;
return '${hours.toString().padLeft(2, '0')}:${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}';
}
