-
안드로이드 CountDownTimer안드로이드 2020. 5. 13. 23:04728x90
오늘은 안드로이드 CountDownTimer 에 대해 알아볼거에요
일정 주기로 어떤 작업을 해야할 때 편하게 쓸 수 있어요. 예를 들면 타이머..? 같은거는 1초 주기로 ++ 하는 작업인거죠
워낙 간단해서 예제 보고 설명할게요
<layout/activity_main.xml>
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <Button android:id="@+id/btn" android:text="버튼" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
<MainActivity.java>
package kr.co.sample; import android.os.Bundle; import android.os.CountDownTimer; import android.view.View; import android.widget.Button; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { Button btn; // 타이머 객체 CountDownTimer timer; int count; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 타이머 객체 정의 timer = new CountDownTimer(5000, 1000) { @Override public void onTick(long millisUntilFinished) { btn.setText(String.valueOf(count++)); } @Override public void onFinish() { btn.setText("끝"); } }; btn = findViewById(R.id.btn); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 타이머 실행 timer.start(); } }); } }
클릭하면 타이머 객체가 실행되면서 count++ 을 하고 있어요
CountDownTimer 의 첫 번째 인자 5000은 전체 5초를 의미
두 번째 인자 1000은 tick 이 실행되는 주기 1초에요
즉 5초동안 1초에 한 번 씩 onTick() 이 실행되고 5초가 지나면 onFinish() 가 호출됩니다.
저희가 이 전까지 AsyncTask 랑 스레드 같은걸 쓰면서 작업 스레드에서는 화면 제어를 할 수 없다는 것을 배웠어요.
여기서 생각을 이어가보면 onTick 에서 btn.setText() 를 해도 에러가 나지 않으니 메인스레드에서 실행됨을 알 수 있죠
그럼 어떻게 메인스레드로 작업스레드 효과를 내는 것일까요?
<CountDownTimer>
@Override public void handleMessage(Message msg) { long lastTickStart = SystemClock.elapsedRealtime(); onTick(millisLeft); // take into account user's onTick taking time to execute long lastTickDuration = SystemClock.elapsedRealtime() - lastTickStart; long delay; if (millisLeft < mCountdownInterval) { // just delay until done delay = millisLeft - lastTickDuration; // special case: user's onTick took more than interval to // complete, trigger onFinish without delay if (delay < 0) delay = 0; } else { delay = mCountdownInterval - lastTickDuration; // special case: user's onTick took more than interval to // complete, skip to next interval while (delay < 0) delay += mCountdownInterval; } sendMessageDelayed(obtainMessage(MSG), delay); }
핸들러에 대한 사전 지식이 필요하니 잘 모르신다면 이 전 글을 참고해주세요!!
2020/05/09 - [Android & Kotlin] - 안드로이드 Looper, Message Queue, Handler
2020/05/09 - [Android & Kotlin] - 안드로이드 핸들러
코드를 잘 보시면 onTick() 을 호출 한 뒤에 delay 를 통해 시간 계산을 하고, sendMessageDelayed() 를 통해 메시지를 보내고 있어요
저 메시지가 도착하면 다시 맨 위 onTick() 이 호출되는 구조에요
즉 메인 스레드에서 onTick() -> 1초 뒤 Message 전달 -> MessageQueue에서 처리 = onTick() -> 1초 뒤 Message 전달 -> MessageQueue에서 처리 = onTick() -> ... -> onFinish()
sleep 을 이용하는 기법은 메인스레드가 sleep 시간동안 잠들지만 이런식으로 구현하면 잠들지 않고 onTick() 을 호출할 수 있어요
delay 계산하는 수식은 남은 시간에 대해 보정하는거에요
우리가 sendMessageDelayed() 를 통해 메시지를 일정 시간 뒤에 보내지만 이게 바로 처리되지 않아요
MessageQueue 안에 값이 많이 들어있으면 1.2초 뒤에 처리될 수도 있는거죠
이럴 때 뒤이어 나오는 onTick() 의 경우 sendMessageDelayed() 에 1000이 아니라 0.2초만큼 보정한 800을 넣어 최대한 유저가 원하는 tick 주기(interval)를 맞춰줘요
'안드로이드' 카테고리의 다른 글
안드로이드 서비스 (0) 2020.05.21 안드로이드 HandlerThread (0) 2020.05.13 Android AsyncTask (0) 2020.05.10 안드로이드 Looper, Message Queue, Handler (0) 2020.05.09 안드로이드 핸들러 (0) 2020.05.09