{"id":1903,"date":"2023-06-08T17:46:04","date_gmt":"2023-06-08T08:46:04","guid":{"rendered":"http:\/\/batmask.dothome.co.kr\/?p=1903"},"modified":"2025-09-11T18:54:52","modified_gmt":"2025-09-11T09:54:52","slug":"deskclock-%ec%bd%94%eb%93%9c%eb%b6%84%ec%84%9d-3-timer%ec%9d%98-%ec%a0%80%ec%9e%a5-%eb%b0%8f-sleep-reboot%eb%93%b1-%ec%b2%98%eb%a6%ac-%ea%b7%b8%eb%a6%ac%ea%b3%a0-%eb%a7%88%eb%ac%b4%eb%a6%ac","status":"publish","type":"post","link":"http:\/\/batmask.net\/index.php\/2023\/06\/08\/1903\/","title":{"rendered":"DeskClock \ucf54\ub4dc\ubd84\uc11d #3 : Timer\uc758 \uc800\uc7a5 \ubc0f Sleep, reboot\ub4f1 \ucc98\ub9ac \uadf8\ub9ac\uace0 \ub9c8\ubb34\ub9ac \uc815\ub9ac"},"content":{"rendered":"\n<p> DeskClock\uc740 \uc2e4\ud589\uc911\uc5d0 wakelock\uc744 \uc694\uccad\ud558\uc9c0 \uc54a\ub294\ub2e4. wakelock\uc744 \uc694\uccad\ud558\ub294 \ubd80\ubd84\uc740 \uc54c\ub78c\uc774 \uc6b8\ub9ac\ub294 \uacbd\uc6b0\uc5d0\ub9cc \uaebc\uc9c0\uc9c0 \uc54a\uace0 \uc54c\ub78c\uc744 \uc6b8\ub9ac\ub3c4\ub85d \uc694\uccad\ud55c\ub2e4. \uc54c\ub78c \ub9e4\ub2c8\uc800\ub97c \ud1b5\ud574 \ube0c\ub85c\ub4dc\uce90\uc2a4\ud2b8 \ub9ac\uc2dc\ubc84\ub85c &#8220;times_up&#8221; \uc778\ud150\ud2b8\ub97c \uc811\uc218\ud558\uba74, TimerService\ub97c \uc2e4\ud589\ud558\uace0 TimerModel.updateTimer()\uac00 \ubd88\ub9b0\ub2e4. \uc5ec\uae30\uc11c doUpdateTimer()\ub97c \ud638\ucd9c\ud558\ub294\ub370, \uc5ec\uae30\uc11c updateRinger() \uc548\uc5d0\uc11c wakelock\uc744 \uc694\uccad\ud558\uace0 \ud574\uc81c\ud55c\ub2e4.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-Roboto-Mono.ttf\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-Roboto-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#adbac7;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#22272e\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#adbac7;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>...\nAlarmAlertWakeLock.acquireScreenCpuWakeLock(mContext)\n...\nAlarmAlertWakeLock.releaseCpuLock()<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki github-dark-dimmed\" style=\"background-color: #22272e\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #F47067\">..<\/span><span style=\"color: #ADBAC7\">.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">AlarmAlertWakeLock.<\/span><span style=\"color: #DCBDFB\">acquireScreenCpuWakeLock<\/span><span style=\"color: #ADBAC7\">(mContext)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F47067\">..<\/span><span style=\"color: #ADBAC7\">.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">AlarmAlertWakeLock.<\/span><span style=\"color: #DCBDFB\">releaseCpuLock<\/span><span style=\"color: #ADBAC7\">()<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>\ud0c0\uc774\uba38\uc758 \uc800\uc7a5\uc740 SharedPreference\ub97c \uc0ac\uc6a9\ud55c\ub2e4. \uac1c\uc778 \ud578\ub4dc\ud3f0\uc5d0\uc11c \uc0ac\uc6a9\ud558\ub294 \ud0c0\uc774\uba38 \uac1c\uc218\uac00 \ub9ce\uc9c0 \uc54a\uc744\uac70\ub77c\uace0 \uac00\uc815\ud55c\ub4ef\ud558\uace0, \uc218\uc2dc\ub85c \uc800\uc7a5\ud558\uace0 \uac00\uc838\uc624\ub294\ub370 \uc801\ud569\ud558\ub2e4\uace0 \ud310\ub2e8\ud55c\uac70\ub77c \ucd94\uce21\ud55c\ub2e4. \uc800\uc7a5 \ubd80\ubd84\uc740 TimerDAO\ub97c \uc0b4\ud3b4\ubcf4\uba74 \ub41c\ub2e4.<\/p>\n\n\n\n<p> \uba3c\uc800 Timer \ud074\ub798\uc2a4\ub97c \ubcf4\uc790. \ud0c0\uc774\uba38\uc5d0 \ub300\ud55c \uc815\ubcf4\uc640 \uacc4\uc0b0\ub4f1\uc774 \ubaa8\ub450 \uc774\ub8e8\uc5b4\uc9c0\ub294 \uacf3\uc774\ub2e4. \uae30\ubcf8\uc801\uc73c\ub85c SharedPreference\uc5d0 \uc800\uc7a5\ub418\ub294 \uad6c\uc870\ub97c \ud3ec\ud568\ud558\uace0 \uc788\uc5b4 \uc544\uc774\ub514, \uc0c1\ud0dc, \uc124\uc815\uc2dc\uac04, \ub0a8\uc740\uc2dc\uac04\ub4f1 \uc5ec\ub7ec \uc815\ubcf4\ub97c \uac00\uc9c0\uace0 \uc788\ub2e4. <\/p>\n\n\n\n<p>\ud765\ubbf8\ub85c\uc6b4 \ubd80\ubd84\uc740 remainingTime \ubcc0\uc218\uc778\ub370, \ub2e4\uc74c\uacfc \uac19\uc774 \uad6c\ud604\ub418\uc5b4 \uc788\ub2e4.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-Roboto-Mono.ttf\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-Roboto-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#adbac7;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#22272e\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#adbac7;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>\/**\n* @return the total amount of time remaining up to this moment; expired and missed timers will\n* return a negative amount\n*\/\nval remainingTime: Long\n    get() {\n        if (state == State.PAUSED || state == State.RESET) {\n            return lastRemainingTime\n        }\n\n        \/\/ In practice, \"now\" can be any value due to device reboots. When the real-time clock\n        \/\/ is reset, there is no more guarantee that \"now\" falls after the last start time. To\n        \/\/ ensure the timer is monotonically decreasing, normalize negative time segments to 0,\n        val timeSinceStart = Utils.now() - lastStartTime\n        return lastRemainingTime - max(0, timeSinceStart)\n    }<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki github-dark-dimmed\" style=\"background-color: #22272e\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #768390\">\/**<\/span><\/span>\n<span class=\"line\"><span style=\"color: #768390\">* <\/span><span style=\"color: #F47067\">@return<\/span><span style=\"color: #768390\"> the total amount of time remaining up to this moment; expired and missed timers will<\/span><\/span>\n<span class=\"line\"><span style=\"color: #768390\">* return a negative amount<\/span><\/span>\n<span class=\"line\"><span style=\"color: #768390\">*\/<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F47067\">val<\/span><span style=\"color: #ADBAC7\"> remainingTime: <\/span><span style=\"color: #F69D50\">Long<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    <\/span><span style=\"color: #F47067\">get<\/span><span style=\"color: #ADBAC7\">() {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">        <\/span><span style=\"color: #F47067\">if<\/span><span style=\"color: #ADBAC7\"> (state <\/span><span style=\"color: #F47067\">==<\/span><span style=\"color: #ADBAC7\"> State.PAUSED <\/span><span style=\"color: #F47067\">||<\/span><span style=\"color: #ADBAC7\"> state <\/span><span style=\"color: #F47067\">==<\/span><span style=\"color: #ADBAC7\"> State.RESET) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">            <\/span><span style=\"color: #F47067\">return<\/span><span style=\"color: #ADBAC7\"> lastRemainingTime<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">        <\/span><span style=\"color: #768390\">\/\/ In practice, &quot;now&quot; can be any value due to device reboots. When the real-time clock<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">        <\/span><span style=\"color: #768390\">\/\/ is reset, there is no more guarantee that &quot;now&quot; falls after the last start time. To<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">        <\/span><span style=\"color: #768390\">\/\/ ensure the timer is monotonically decreasing, normalize negative time segments to 0,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">        <\/span><span style=\"color: #F47067\">val<\/span><span style=\"color: #ADBAC7\"> timeSinceStart <\/span><span style=\"color: #F47067\">=<\/span><span style=\"color: #ADBAC7\"> Utils.<\/span><span style=\"color: #DCBDFB\">now<\/span><span style=\"color: #ADBAC7\">() <\/span><span style=\"color: #F47067\">-<\/span><span style=\"color: #ADBAC7\"> lastStartTime<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">        <\/span><span style=\"color: #F47067\">return<\/span><span style=\"color: #ADBAC7\"> lastRemainingTime <\/span><span style=\"color: #F47067\">-<\/span><span style=\"color: #ADBAC7\"> <\/span><span style=\"color: #DCBDFB\">max<\/span><span style=\"color: #ADBAC7\">(<\/span><span style=\"color: #6CB6FF\">0<\/span><span style=\"color: #ADBAC7\">, timeSinceStart)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    }<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p> PAUSED\ub098 RESET \uc0c1\ud0dc\ub294 \uc2dc\uac04\uc774 \ud750\ub974\ub294 \uc0c1\ud669\uc774 \uc544\ub2c8\ubbc0\ub85c, \uc800\uc7a5\ub41c \uac00\uc7a5 \ucd5c\uadfc\uc758  \ub0a8\uc740\uc2dc\uac04, lastRemainingTime \uc774 \ub9ac\ud134\ub41c\ub2e4. \uadf8\ub2e4\uc74c, \ud0c0\uc774\uba38\uac00 \uc2dc\uc791\ub41c \uc774\ud6c4\ub85c \ud750\ub978 \uc2dc\uac04\uc744 \uacc4\uc0b0\ud558\ub294\ub370,  now()\ub85c \ud604\uc7ac\uc2dc\uac04\uc5d0\uc11c \uac00\uc7a5 \ucd5c\uadfc \uc2dc\uc791\ub41c \uc2dc\uac04\uc778 lastStartTime\uc744 \ube7c\uc918\uc11c \uacc4\uc0b0\ud55c\ub2e4. now()\ub97c \ud55c\ubc88 \uc0b4\ud3b4\ubcf4\uc790.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-Roboto-Mono.ttf\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-Roboto-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#adbac7;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#22272e\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#adbac7;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>fun now(): Long = DataModel.dataModel.elapsedRealtime()\n...\nfun elapsedRealtime(): Long = SystemClock.elapsedRealtime()<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki github-dark-dimmed\" style=\"background-color: #22272e\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #F47067\">fun<\/span><span style=\"color: #ADBAC7\"> <\/span><span style=\"color: #DCBDFB\">now<\/span><span style=\"color: #ADBAC7\">(): <\/span><span style=\"color: #F69D50\">Long<\/span><span style=\"color: #ADBAC7\"> <\/span><span style=\"color: #F47067\">=<\/span><span style=\"color: #ADBAC7\"> DataModel.dataModel.<\/span><span style=\"color: #DCBDFB\">elapsedRealtime<\/span><span style=\"color: #ADBAC7\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F47067\">..<\/span><span style=\"color: #ADBAC7\">.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F47067\">fun<\/span><span style=\"color: #ADBAC7\"> <\/span><span style=\"color: #DCBDFB\">elapsedRealtime<\/span><span style=\"color: #ADBAC7\">(): <\/span><span style=\"color: #F69D50\">Long<\/span><span style=\"color: #ADBAC7\"> <\/span><span style=\"color: #F47067\">=<\/span><span style=\"color: #ADBAC7\"> SystemClock.<\/span><span style=\"color: #DCBDFB\">elapsedRealtime<\/span><span style=\"color: #ADBAC7\">()<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>now()\ub294 \uacb0\uad6d SystemClock.elapsedRealtime()\uc744 \uac00\uc838\uc628\ub2e4. \uc774\uac8c \ubb34\uc2a8 \uac12\uc774\ub0d0\uba74, \ubd80\ud305 \ud6c4 \uc9c0\uae08\uae4c\uc9c0 \ud750\ub978 \uc2dc\uac04\uc73c\ub85c \uc911\uac04\uc5d0 \uc2ac\ub9bd\uc0c1\ud0dc\uc5d0 \ub4e4\uc5b4\uac04 \uc2dc\uac04\ub3c4 \ud3ec\ud568\ud55c\ub2e4. ( <a href=\"https:\/\/developer.android.com\/reference\/android\/os\/SystemClock#elapsedRealtime()\">\uc548\ub4dc\ub85c\uc774\ub4dc \ub808\ud37c\ub7f0\uc2a4 \ubb38\uc11c \ucc38\uc870<\/a> ) lastStartTime\ub3c4 \uc54c\uc544\uc57c \ud558\ub294\ub370, start()\ub97c \uc0b4\ud3b4\ubcf4\uba74,<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-Roboto-Mono.ttf\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-Roboto-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#adbac7;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#22272e\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#adbac7;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>fun start(): Timer {\n    return if (state == State.RUNNING || state == State.EXPIRED || state == State.MISSED) {\n        this\n    } else {\n        Timer(id, State.RUNNING, length, totalLength,\n                Utils.now(), Utils.wallClock(), lastRemainingTime, label, deleteAfterUse)\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki github-dark-dimmed\" style=\"background-color: #22272e\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #F47067\">fun<\/span><span style=\"color: #ADBAC7\"> <\/span><span style=\"color: #DCBDFB\">start<\/span><span style=\"color: #ADBAC7\">(): <\/span><span style=\"color: #F69D50\">Timer<\/span><span style=\"color: #ADBAC7\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    <\/span><span style=\"color: #F47067\">return<\/span><span style=\"color: #ADBAC7\"> <\/span><span style=\"color: #F47067\">if<\/span><span style=\"color: #ADBAC7\"> (state <\/span><span style=\"color: #F47067\">==<\/span><span style=\"color: #ADBAC7\"> State.RUNNING <\/span><span style=\"color: #F47067\">||<\/span><span style=\"color: #ADBAC7\"> state <\/span><span style=\"color: #F47067\">==<\/span><span style=\"color: #ADBAC7\"> State.EXPIRED <\/span><span style=\"color: #F47067\">||<\/span><span style=\"color: #ADBAC7\"> state <\/span><span style=\"color: #F47067\">==<\/span><span style=\"color: #ADBAC7\"> State.MISSED) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">        <\/span><span style=\"color: #6CB6FF\">this<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    } <\/span><span style=\"color: #F47067\">else<\/span><span style=\"color: #ADBAC7\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">        <\/span><span style=\"color: #DCBDFB\">Timer<\/span><span style=\"color: #ADBAC7\">(id, State.RUNNING, length, totalLength,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">                Utils.<\/span><span style=\"color: #DCBDFB\">now<\/span><span style=\"color: #ADBAC7\">(), Utils.<\/span><span style=\"color: #DCBDFB\">wallClock<\/span><span style=\"color: #ADBAC7\">(), lastRemainingTime, label, deleteAfterUse)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p> \ud0c0\uc774\uba38\ub97c \uc2dc\uc791\ud560 \ub54c, Utils.now()\ub85c elapsedRealtime()\uc744 \uac00\uc838\uc640 \uc124\uc815\ud55c\ub2e4. \uacb0\uad6d \ucc98\uc74c\uc73c\ub85c \ub3cc\uc544\uac00\uc11c timeSinceStart\ub294 \ud604\uc7ac elapsedRealtime()\uc5d0\uc11c \ud0c0\uc774\uba38 \uc2dc\uc791\uc2dc\uc810\uc758 elapsedRealtime()\uc744 \ube7c\uc8fc\uc5b4 \uc2dc\uc791 \ud6c4 \ud750\ub978\uc2dc\uac04\uac12\uc744 \uac16\ub294\ub2e4. <\/p>\n\n\n\n<p>lastRemainingTime\uc774 \uc5b8\uc81c \uc5b4\ub5bb\uac8c \uc124\uc815\ub418\ub0d0\uac00 \ubb38\uc81c\uc778\ub370 \uc77c\ub2e8, \ucc98\uc74c Timer \uc0dd\uc131\uc2dc length\ub85c \uc124\uc815\ub41c\ub2e4. <\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-Roboto-Mono.ttf\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-Roboto-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#adbac7;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#22272e\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#adbac7;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>fun addTimer(length: Long, label: String?, deleteAfterUse: Boolean): Timer {\n    \/\/ Create the timer instance.\n    var timer =\n        Timer(-1, Timer.State.RESET, length, length, Timer.UNUSED, Timer.UNUSED, length,\n        label, deleteAfterUse)\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki github-dark-dimmed\" style=\"background-color: #22272e\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #F47067\">fun<\/span><span style=\"color: #ADBAC7\"> <\/span><span style=\"color: #DCBDFB\">addTimer<\/span><span style=\"color: #ADBAC7\">(length: <\/span><span style=\"color: #F69D50\">Long<\/span><span style=\"color: #ADBAC7\">, label: <\/span><span style=\"color: #F69D50\">String<\/span><span style=\"color: #ADBAC7\">?, deleteAfterUse: <\/span><span style=\"color: #F69D50\">Boolean<\/span><span style=\"color: #ADBAC7\">): <\/span><span style=\"color: #F69D50\">Timer<\/span><span style=\"color: #ADBAC7\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    <\/span><span style=\"color: #768390\">\/\/ Create the timer instance.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    <\/span><span style=\"color: #F47067\">var<\/span><span style=\"color: #ADBAC7\"> timer <\/span><span style=\"color: #F47067\">=<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">        <\/span><span style=\"color: #DCBDFB\">Timer<\/span><span style=\"color: #ADBAC7\">(<\/span><span style=\"color: #F47067\">-<\/span><span style=\"color: #6CB6FF\">1<\/span><span style=\"color: #ADBAC7\">, Timer.State.RESET, length, length, Timer.UNUSED, Timer.UNUSED, length,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">        label, deleteAfterUse)<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p>\uadf8 \uc678\uc5d0 1\ubd84\uc529 \ucd94\uac00\ud558\ub294 \uacbd\uc6b0\ub098, \uc2dc\uac04 \uae38\uc774\uac00 \ubcc0\ud560 \ub54c, \ucd94\uac00\ub41c \uc2dc\uac04\uc744 \ud3ec\ud568\ud558\uc5ec \uc0c8\ub85c \uc124\uc815\ub41c\ub2e4. \ub610\ud55c, pause()\ud568\uc218\uc5d0\uc11c \ud604\uc7ac remainingtime\uc73c\ub85c \uc124\uc815\ud558\uace0 \uc788\ub2e4. <\/p>\n\n\n\n<p> \ubb54\uac00 \ubcf5\uc7a1\ud55c\ub370, \uacb0\uad6d\uc5d0 timer\uac00 pause\ub418\uc9c0 \uc54a\uc73c\uba74, \uc804\uccb4 \uc2dc\uac04\uc774 lastRemainingTime\uc774 \ub41c\ub2e4(missed \ub098 expired \ub294 \uc608\uc678\uc0c1\ud669). \uadf8\ub798\uc11c lastRemainingTime &#8211; max(0, timeSinceStart)\uac00 \ub0a8\uc740 \uc2dc\uac04(remaining time)\uc774 \ub41c\ub2e4. max()\ub97c \uc0ac\uc6a9\ud558\ub294 \uc774\uc720\ub294, lastRemainingTime\uc774 \ub9c8\uc774\ub108\uc2a4\uac00 \ub420 \uac83\uc744 \uc0dd\uac01\ud574\uc11c \ub4e4\uc5b4\uac04\uac70 \uac19\uc740\ub370, \uc2e4\uc81c\ub85c \ub9c8\uc774\ub108\uc2a4\uac00 \ub420 \uc0c1\ud669\uc774 \uc5c6\uc5b4\ubcf4\uc774\uae34 \ud55c\ub2e4. <\/p>\n\n\n\n<p>\uc608\uc678\uc0c1\ud669\uc73c\ub85c reboot\uc774 \uc77c\uc5b4\ub0ac\uc744 \ub54c, \uc2dc\uc2a4\ud15c \uc2dc\uac04\uc774 \ubcc0\uacbd\ub410\uc744 \ub54c\uc758 \ucc98\ub9ac\uac00 \uc788\ub2e4. AlarmInitReceiver\uc5d0\uc11c \uc6b0\uc120 \uc2dc\uc2a4\ud15c \ubcc0\uacbd intent\ub97c \ubc1b\ub294\ub2e4. <\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-Roboto-Mono.ttf\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-Roboto-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#adbac7;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#22272e\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#adbac7;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>if (ACTION_BOOT_COMPLETED == action) {\n    DataModel.dataModel.updateAfterReboot()\n    \/\/ Stopwatch and timer data need to be updated on time change so the reboot\n    \/\/ functionality works as expected.\n} else if (Intent.ACTION_TIME_CHANGED == action) {\n    DataModel.dataModel.updateAfterTimeSet()\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki github-dark-dimmed\" style=\"background-color: #22272e\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #F47067\">if<\/span><span style=\"color: #ADBAC7\"> (ACTION_BOOT_COMPLETED <\/span><span style=\"color: #F47067\">==<\/span><span style=\"color: #ADBAC7\"> action) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    DataModel.dataModel.<\/span><span style=\"color: #DCBDFB\">updateAfterReboot<\/span><span style=\"color: #ADBAC7\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    <\/span><span style=\"color: #768390\">\/\/ Stopwatch and timer data need to be updated on time change so the reboot<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    <\/span><span style=\"color: #768390\">\/\/ functionality works as expected.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">} <\/span><span style=\"color: #F47067\">else<\/span><span style=\"color: #ADBAC7\"> <\/span><span style=\"color: #F47067\">if<\/span><span style=\"color: #ADBAC7\"> (Intent.ACTION_TIME_CHANGED <\/span><span style=\"color: #F47067\">==<\/span><span style=\"color: #ADBAC7\"> action) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    DataModel.dataModel.<\/span><span style=\"color: #DCBDFB\">updateAfterTimeSet<\/span><span style=\"color: #ADBAC7\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>\ud638\ucd9c \uccb4\uc778\uc744 \ub530\ub77c\uac00\ubcf4\uba74, Timer\uc758 updateAfterReboot()\uacfc updateAfterTimeSet()\uc5d0 \ub3c4\ub2ec\ud55c\ub2e4. \uc6b0\uc120 rebooting\uc2dc\uc5d0\ub294 wallClock, \uc2e4\uc81c\ub85c\ub294 System.currentTimeMillis()\ub97c \uac00\uc9c0\uace0 \ub9c8\uc9c0\ub9c9\uc5d0 \uc800\uc7a5\ub41c \uac12\uacfc \ud604\uc7ac\uac12\uc744 \ube44\uad50\ud558\uc5ec \ub9ac\ubd80\ud305 \uacfc\uc815\uc5d0\uc11c \ud750\ub978 \uc2dc\uac04 delta\ub97c \uacc4\uc0b0\ud55c\ub2e4. \uc0c8\ub85c\uc6b4 remaining time\uc740 lastRemainingTime\uc5d0\uc11c delta\ub97c \ube7c\uc8fc\uc5b4 \uc5bb\uac8c\ub41c\ub2e4. \uc774\uac78 \uc0c8\ub85c\uc6b4 \ud0c0\uc774\uba38\ub85c \uc0ac\uc6a9\ud55c\ub2e4. <\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-Roboto-Mono.ttf\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-Roboto-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#adbac7;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#22272e\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#adbac7;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>fun updateAfterReboot(): Timer {\n    if (state == State.RESET || state == State.PAUSED) {\n        return this\n    }\n    val timeSinceBoot = Utils.now()\n    val wallClockTime = Utils.wallClock()\n    \/\/ Avoid negative time deltas. They can happen in practice, but they can't be used. Simply\n    \/\/ update the recorded times and proceed with no change in accumulated time.\n    val delta = max(0, wallClockTime - lastWallClockTime)\n    val remainingTime = lastRemainingTime - delta\n    return Timer(id, state, length, totalLength, timeSinceBoot, wallClockTime,\n            remainingTime, label, deleteAfterUse)\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki github-dark-dimmed\" style=\"background-color: #22272e\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #F47067\">fun<\/span><span style=\"color: #ADBAC7\"> <\/span><span style=\"color: #DCBDFB\">updateAfterReboot<\/span><span style=\"color: #ADBAC7\">(): <\/span><span style=\"color: #F69D50\">Timer<\/span><span style=\"color: #ADBAC7\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    <\/span><span style=\"color: #F47067\">if<\/span><span style=\"color: #ADBAC7\"> (state <\/span><span style=\"color: #F47067\">==<\/span><span style=\"color: #ADBAC7\"> State.RESET <\/span><span style=\"color: #F47067\">||<\/span><span style=\"color: #ADBAC7\"> state <\/span><span style=\"color: #F47067\">==<\/span><span style=\"color: #ADBAC7\"> State.PAUSED) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">        <\/span><span style=\"color: #F47067\">return<\/span><span style=\"color: #ADBAC7\"> <\/span><span style=\"color: #6CB6FF\">this<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    <\/span><span style=\"color: #F47067\">val<\/span><span style=\"color: #ADBAC7\"> timeSinceBoot <\/span><span style=\"color: #F47067\">=<\/span><span style=\"color: #ADBAC7\"> Utils.<\/span><span style=\"color: #DCBDFB\">now<\/span><span style=\"color: #ADBAC7\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    <\/span><span style=\"color: #F47067\">val<\/span><span style=\"color: #ADBAC7\"> wallClockTime <\/span><span style=\"color: #F47067\">=<\/span><span style=\"color: #ADBAC7\"> Utils.<\/span><span style=\"color: #DCBDFB\">wallClock<\/span><span style=\"color: #ADBAC7\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    <\/span><span style=\"color: #768390\">\/\/ Avoid negative time deltas. They can happen in practice, but they can&#39;t be used. Simply<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    <\/span><span style=\"color: #768390\">\/\/ update the recorded times and proceed with no change in accumulated time.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    <\/span><span style=\"color: #F47067\">val<\/span><span style=\"color: #ADBAC7\"> delta <\/span><span style=\"color: #F47067\">=<\/span><span style=\"color: #ADBAC7\"> <\/span><span style=\"color: #DCBDFB\">max<\/span><span style=\"color: #ADBAC7\">(<\/span><span style=\"color: #6CB6FF\">0<\/span><span style=\"color: #ADBAC7\">, wallClockTime <\/span><span style=\"color: #F47067\">-<\/span><span style=\"color: #ADBAC7\"> lastWallClockTime)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    <\/span><span style=\"color: #F47067\">val<\/span><span style=\"color: #ADBAC7\"> remainingTime <\/span><span style=\"color: #F47067\">=<\/span><span style=\"color: #ADBAC7\"> lastRemainingTime <\/span><span style=\"color: #F47067\">-<\/span><span style=\"color: #ADBAC7\"> delta<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    <\/span><span style=\"color: #F47067\">return<\/span><span style=\"color: #ADBAC7\"> <\/span><span style=\"color: #DCBDFB\">Timer<\/span><span style=\"color: #ADBAC7\">(id, state, length, totalLength, timeSinceBoot, wallClockTime,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">            remainingTime, label, deleteAfterUse)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>\uc2dc\uac04\uc774 \ubcc0\uacbd\ub41c \uacbd\uc6b0\uc5d0\ub294 elapsedRealtime\uc744 \uac00\uc838\uc640\uc11c \uc2dc\uc791\uc2dc \uc800\uc7a5\ud55c elapsedRealtime\uc778 lastStartTime\uacfc\uc758 \ucc28\uc774\ub97c \uac00\uc9c0\uace0 \uacc4\uc0b0\ud55c\ub2e4. <\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-Roboto-Mono.ttf\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-Roboto-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#adbac7;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#22272e\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#adbac7;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>fun updateAfterTimeSet(): Timer {\n    if (state == State.RESET || state == State.PAUSED) {\n        return this\n    }\n    val timeSinceBoot = Utils.now()\n    val wallClockTime = Utils.wallClock()\n    val delta = timeSinceBoot - lastStartTime\n    val remainingTime = lastRemainingTime - delta\n    return if (delta &lt; 0) {\n        \/\/ Avoid negative time deltas. They typically happen following reboots when TIME_SET is\n        \/\/ broadcast before BOOT_COMPLETED. Simply ignore the time update and hope\n        \/\/ updateAfterReboot() can successfully correct the data at a later time.\n        this\n    } else {\n        Timer(id, state, length, totalLength, timeSinceBoot, wallClockTime,\n                remainingTime, label, deleteAfterUse)\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki github-dark-dimmed\" style=\"background-color: #22272e\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #F47067\">fun<\/span><span style=\"color: #ADBAC7\"> <\/span><span style=\"color: #DCBDFB\">updateAfterTimeSet<\/span><span style=\"color: #ADBAC7\">(): <\/span><span style=\"color: #F69D50\">Timer<\/span><span style=\"color: #ADBAC7\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    <\/span><span style=\"color: #F47067\">if<\/span><span style=\"color: #ADBAC7\"> (state <\/span><span style=\"color: #F47067\">==<\/span><span style=\"color: #ADBAC7\"> State.RESET <\/span><span style=\"color: #F47067\">||<\/span><span style=\"color: #ADBAC7\"> state <\/span><span style=\"color: #F47067\">==<\/span><span style=\"color: #ADBAC7\"> State.PAUSED) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">        <\/span><span style=\"color: #F47067\">return<\/span><span style=\"color: #ADBAC7\"> <\/span><span style=\"color: #6CB6FF\">this<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    <\/span><span style=\"color: #F47067\">val<\/span><span style=\"color: #ADBAC7\"> timeSinceBoot <\/span><span style=\"color: #F47067\">=<\/span><span style=\"color: #ADBAC7\"> Utils.<\/span><span style=\"color: #DCBDFB\">now<\/span><span style=\"color: #ADBAC7\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    <\/span><span style=\"color: #F47067\">val<\/span><span style=\"color: #ADBAC7\"> wallClockTime <\/span><span style=\"color: #F47067\">=<\/span><span style=\"color: #ADBAC7\"> Utils.<\/span><span style=\"color: #DCBDFB\">wallClock<\/span><span style=\"color: #ADBAC7\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    <\/span><span style=\"color: #F47067\">val<\/span><span style=\"color: #ADBAC7\"> delta <\/span><span style=\"color: #F47067\">=<\/span><span style=\"color: #ADBAC7\"> timeSinceBoot <\/span><span style=\"color: #F47067\">-<\/span><span style=\"color: #ADBAC7\"> lastStartTime<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    <\/span><span style=\"color: #F47067\">val<\/span><span style=\"color: #ADBAC7\"> remainingTime <\/span><span style=\"color: #F47067\">=<\/span><span style=\"color: #ADBAC7\"> lastRemainingTime <\/span><span style=\"color: #F47067\">-<\/span><span style=\"color: #ADBAC7\"> delta<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    <\/span><span style=\"color: #F47067\">return<\/span><span style=\"color: #ADBAC7\"> <\/span><span style=\"color: #F47067\">if<\/span><span style=\"color: #ADBAC7\"> (delta <\/span><span style=\"color: #F47067\">&lt;<\/span><span style=\"color: #ADBAC7\"> <\/span><span style=\"color: #6CB6FF\">0<\/span><span style=\"color: #ADBAC7\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">        <\/span><span style=\"color: #768390\">\/\/ Avoid negative time deltas. They typically happen following reboots when TIME_SET is<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">        <\/span><span style=\"color: #768390\">\/\/ broadcast before BOOT_COMPLETED. Simply ignore the time update and hope<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">        <\/span><span style=\"color: #768390\">\/\/ updateAfterReboot() can successfully correct the data at a later time.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">        <\/span><span style=\"color: #6CB6FF\">this<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    } <\/span><span style=\"color: #F47067\">else<\/span><span style=\"color: #ADBAC7\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">        <\/span><span style=\"color: #DCBDFB\">Timer<\/span><span style=\"color: #ADBAC7\">(id, state, length, totalLength, timeSinceBoot, wallClockTime,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">                remainingTime, label, deleteAfterUse)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ADBAC7\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>\uc0dd\uac01\ubcf4\ub2e4 \ubb54\uac00 \ubcf5\uc7a1\ud558\uac8c \uad6c\ud604\uc774 \ub418\uc5b4 \uc788\uc5b4 \ud558\ub098\ud558\ub098 \uc774\ud574\ud558\ub294\ub370 \uc790\uafb8 \ube0c\ub808\uc774\ud06c\uac00 \uac78\ub838\ub2e4. lastStartTime\uc774 elapsedRealtime()\uc73c\ub85c \uae30\ub85d\ub418\uace0 lastRemaingTime\uc774 \uc2dc\uac04\uc758 \ud750\ub984\uc5d0 \ub530\ub77c \uacc4\uc18d \uc5c5\ub370\uc774\ud2b8 \ub418\ub294\uac8c \uc544\ub2c8\ub77c pause\uac19\uc740 \uc774\ubca4\ud2b8\uc2dc\uc5d0\ub9cc \uc5c5\ub370\uc774\ud2b8 \ub418\ub294\uac8c \ud63c\ub780\uc2a4\ub7ec\uc6e0\ub358\uac70 \uac19\ub2e4. \uc804\uccb4\uc801\uc778 \ud750\ub984\uacfc \uac1c\ub150\ub9cc \uc798 \uc7a1\uace0 \ub118\uc5b4\uac00\uba74 \ub420\uac70\uac19\ub2e4.<\/p>\n\n\n\n<p style=\"font-style:normal;font-weight:700\"> \uc774\ub85c\uc11c \uacf5\uc2dd Timer\uc571\uc758 \uac00\uc7a5 \ud070 \uad81\uae08\uc99d\ub4e4\uc774 \ud480\ub838\ub2e4. \ub300\ucda9 \ub2e4\uc74c\uacfc \uac19\uc774 \ud0c0\uc774\uba38 \ubd84\uc11d\uc744 \uc815\ub9ac\ud560 \uc218 \uc788\uaca0\ub2e4.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li style=\"font-style:normal;font-weight:700\">\ud0c0\uc774\uba38\ub4e4\uc758 \uc800\uc7a5 \ubc0f \uad00\ub9ac? : SharedPreference\ub85c \uc774\ub8e8\uc5b4\uc9c4\ub2e4<\/li>\n\n\n\n<li style=\"font-style:normal;font-weight:700\">\ud0c0\uc774\uba38 \uc2e4\ud589\uc911\uc5d0 wakelock\uc744 \uac78\uace0 \ub3cc\ub9ac\ub294\uac74\uc9c0? : \uc54c\ub78c \uc6b8\ub9b4 \ub54c \ube7c\uace4 \ud544\uc694\uc5c6\ub2e4. AlarmManager\ub97c \uc774\uc6a9\ud574 \ub9cc\uae30\ub420 \ub54c \uae68\uc6b0\uba74\uc11c \uc54c\ub78c \uc6b8\ub9ac\uace0, \uc911\uac04\uc5d0 \uc2ac\ub9bd \ub4e4\uc5b4\uac00\uba74 elapsedRealTime()\uc73c\ub85c \ud750\ub978 \uc2dc\uac04\uc744 \uacc4\uc0b0, \uc5c5\ub370\uc774\ud2b8\ud574 \uc0ac\uc6a9\ud55c\ub2e4.<\/li>\n\n\n\n<li style=\"font-style:normal;font-weight:700\">Service\ub97c \uc5b4\ub5bb\uac8c \uc0ac\uc6a9\ud558\ub294\uc9c0, Notification\uacfc App\uac04\uc758 \uc804\ud658\uc740? : Service\ub294 onStartCommand()\ud615\ud0dc\ub85c \uc0c1\uc8fc\ud558\ub294 \uc11c\ube44\uc2a4\uac00 \uc544\ub2c8\ub77c \ucee4\ub9e8\ub4dc \ucc98\ub9ac\uae30\uc815\ub3c4\uc758 \uc911\uacc4 \uc5ed\ud560\ub9cc \ud55c\ub2e4. Notification\uc740 \uba54\uc778 Activity\uc778 DeskClock\uc758 onStart(), onStop()\uc5d0\uc11c \uc2e4\ud589, \uc81c\uac70\ub97c \ud574\uc900\ub2e4. <\/li>\n<\/ol>\n\n\n\n<p style=\"font-style:normal;font-weight:700\">\ud0c0\uc774\uba38\ub97c \ud2f1\ub9c8\ub2e4 \uacc4\uc18d \uacc4\uc0b0\ud558\ub294 \uac1c\ub150\uc774 \uc544\ub2c8\uace0, UI\uc5c5\ub370\uc774\ud2b8\uc2dc \ub0a8\uc740\uc2dc\uac04\uc744 \uacc4\uc18d \uacc4\uc0b0\ud574\uc11c \ubcf4\uc5ec\uc8fc\ub294 \ubc29\uc2dd\uc774\ub2e4. \ub2e4\ub9cc, UI\uac00 \ubcf4\uc5ec\uc9c0\ub294 \uacbd\uc6b0\uc5d0\ub294 UI\ub97c \ud2f1\ub9c8\ub2e4 \uacc4\uc18d \uc5c5\ub370\uc774\ud2b8 \ud574\uc900\ub2e4. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>DeskClock\uc740 \uc2e4\ud589\uc911\uc5d0 wakelock\uc744 \uc694\uccad\ud558\uc9c0 \uc54a\ub294\ub2e4. wakelock\uc744 \uc694\uccad\ud558\ub294 \ubd80\ubd84\uc740 \uc54c\ub78c\uc774 \uc6b8\ub9ac\ub294 \uacbd\uc6b0\uc5d0\ub9cc \uaebc\uc9c0\uc9c0 \uc54a\uace0 \uc54c\ub78c\uc744 \uc6b8\ub9ac\ub3c4\ub85d \uc694\uccad\ud55c\ub2e4. \uc54c\ub78c \ub9e4\ub2c8\uc800\ub97c \ud1b5\ud574 \ube0c\ub85c\ub4dc\uce90\uc2a4\ud2b8 \ub9ac\uc2dc\ubc84\ub85c &#8220;times_up&#8221; \uc778\ud150\ud2b8\ub97c \uc811\uc218\ud558\uba74, TimerService\ub97c \uc2e4\ud589\ud558\uace0 TimerModel.updateTimer()\uac00 \ubd88\ub9b0\ub2e4. \uc5ec\uae30\uc11c doUpdateTimer()\ub97c \ud638\ucd9c\ud558\ub294\ub370, \uc5ec\uae30\uc11c updateRinger() \uc548\uc5d0\uc11c wakelock\uc744 \uc694\uccad\ud558\uace0 \ud574\uc81c\ud55c\ub2e4. \ud0c0\uc774\uba38\uc758 \uc800\uc7a5\uc740 SharedPreference\ub97c \uc0ac\uc6a9\ud55c\ub2e4. \uac1c\uc778 \ud578\ub4dc\ud3f0\uc5d0\uc11c \uc0ac\uc6a9\ud558\ub294 \ud0c0\uc774\uba38 \uac1c\uc218\uac00 \ub9ce\uc9c0 \uc54a\uc744\uac70\ub77c\uace0 \uac00\uc815\ud55c\ub4ef\ud558\uace0, \uc218\uc2dc\ub85c \uc800\uc7a5\ud558\uace0 \uac00\uc838\uc624\ub294\ub370 \uc801\ud569\ud558\ub2e4\uace0 \ud310\ub2e8\ud55c\uac70\ub77c \ucd94\uce21\ud55c\ub2e4. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,34],"tags":[186,311,38,283],"class_list":["post-1903","post","type-post","status-publish","format-standard","hentry","category-android","category-kotlin","tag-android-2","tag-deskclock","tag-kotlin","tag-timer"],"jetpack_featured_media_url":"","_links":{"self":[{"href":"http:\/\/batmask.net\/index.php\/wp-json\/wp\/v2\/posts\/1903","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/batmask.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/batmask.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/batmask.net\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/batmask.net\/index.php\/wp-json\/wp\/v2\/comments?post=1903"}],"version-history":[{"count":8,"href":"http:\/\/batmask.net\/index.php\/wp-json\/wp\/v2\/posts\/1903\/revisions"}],"predecessor-version":[{"id":3467,"href":"http:\/\/batmask.net\/index.php\/wp-json\/wp\/v2\/posts\/1903\/revisions\/3467"}],"wp:attachment":[{"href":"http:\/\/batmask.net\/index.php\/wp-json\/wp\/v2\/media?parent=1903"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/batmask.net\/index.php\/wp-json\/wp\/v2\/categories?post=1903"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/batmask.net\/index.php\/wp-json\/wp\/v2\/tags?post=1903"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}