ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 안드로이드 CountDownTimer
    안드로이드 2020. 5. 13. 23:04
    728x90

    오늘은 안드로이드 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] - 안드로이드 핸들러

     

    안드로이드 핸들러

    2020/05/09 - [Android & Kotlin] - 안드로이드 Looper, Message Queue 2020/05/09 - [Android & Kotlin] - 안드로이드 스레드 2020/05/09 - [Android & Kotlin] - 안드로이드 멀티스레드 이전 글들을 통해서 메인..

    bubble-dev.tistory.com

    코드를 잘 보시면 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

    댓글

Designed by Tistory.