아주 간단하게, 디자인은 거의 생각하지 않고,
시계 동작 구현에 우선 순위를 두어 만들어 본 간단 시계입니다.
(추가 내용 : TextClock 을 추가하여, TextClock 동작과 간단 시계 동작을 확인합니다.)
레이아웃 구성
- tv_time
: 날짜 표시 TextView
- tv_date
: 시간 표시 TextView
(24 시간 표시 형식)
(추가 내용 : text_clock
: 시간 표시 TextClock
)
activity_main.xml 전체 코드
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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"
tools:context=".MainActivity">
<!-- 날짜 표시 TextView -->
<TextView
android:id="@+id/tv_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:text="2022.12.25 (일)"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!-- 시간 표시 TextView -->
<TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="00:00:00"
android:textSize="50sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!-- 추가 내용 : TextClock -->
<TextClock
android:id="@+id/text_clock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="150dp"
android:textSize="50sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:format24Hour="HH:mm:ss"
android:format12Hour="hh:mm:ss"
/>
</android.support.constraint.ConstraintLayout>
<TextClock />
- 간단 시계가 정상적으로 동작하는 지 확인용입니다.
(이 확인으로 간단 시계의 초가 미묘하게 맞지 않는 것을 확인했습니다.) - 제거 하려면, 위 코드에서
<TextClock />
태그 내용 전체를 삭제하면 됩니다. - java 코드 수정 없이, 이 태그 코드만으로도 시계가 표시됩니다.
- 시스템(휴대폰) 설정에 따라 24시간, 12시간 형식으로 보여집니다.
- 시스템 설정 확인 (기기에 따라 다를 수 있음) : 설정 > 일반 > 날짜 및 시간 > 24시간 형식 사용 여부
- HH:mm:ss 포맷 설정에 대해 더 자세히 알려면 DateTimeFormatter 문서를 확인하세요.
[ DateTimeFormatter 중 시간 부분 ]
h | clock-hour-of-am-pm (1-12) | number | 12 |
K | hour-of-am-pm (0-11) | number | 0 |
k | clock-hour-of-day (1-24) | number | 24 |
H | hour-of-day (0-23) | number | 0 |
MainActivity.java 전체 코드
package com.example.clockver01;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import java.util.Calendar;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
public class MainActivity extends AppCompatActivity {
final Handler handler = new Handler(Looper.getMainLooper());
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tvDate = (TextView) findViewById(R.id.tv_date);
TextView tvTime = (TextView) findViewById(R.id.tv_time);
Timer timer = new Timer();
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
handler.post(new Runnable() {
@Override
public void run() {
Calendar current = Calendar.getInstance();
int year = current.get(Calendar.YEAR);
int month = current.get(Calendar.MONDAY);
int day = current.get(Calendar.DATE);
String dayWeek = current.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.SHORT, Locale.KOREA);
int hour = current.get(Calendar.HOUR_OF_DAY);
int minute = current.get(Calendar.MINUTE);
int second = current.get(Calendar.SECOND);
month = month + 1; // 월은 0~11, 1을 더해줘야 함
tvDate.setText(String.format("%04d.%02d.%02d (%s)", year, month, day, dayWeek));
tvTime.setText(String.format("%02d:%02d:%02d", hour, minute, second));
}
});
}
};
// 추가 : 0 millisecond 에 시작되도록 지연 시간 계산
Calendar startTick = Calendar.getInstance();
int delay = 1000 - startTick.get(Calendar.MILLISECOND);
if(delay == 1000){
delay = 0;
}
// 함수가 실행하면서 생긴 지연 시간을 무시
timer.scheduleAtFixedRate(timerTask, delay, 1000);
// 수정 전 : 선행 작업(가비지 컬렉션 등)으로 지연이 발생할 수 있음
//timer.schedule(timerTask, 0, 1000);
}
}
코드 간략 설명
Timer
- delay
: 0 => 즉시 시작, 여기서는 0 millisecond에 시작되도록 위에서 delay 시간 계산 함
- period
: 1000 => 1초 간격
- scheduleAtFixedRate
사용
Timer timer = new Timer();
// 함수가 실행하면서 생긴 지연 시간을 무시
timer.scheduleAtFixedRate(timerTask, delay, 1000);
// 수정 전 : 선행 작업(가비지 컬렉션 등)으로 지연이 발생할 수 있음
//timer.schedule(timerTask, 0, 1000);
참고 ) Timer
class의 scheduleAtFixedRate
메서드
public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
if (delay < 0)
throw new IllegalArgumentException("Negative delay.");
if (period <= 0)
throw new IllegalArgumentException("Non-positive period.");
sched(task, System.currentTimeMillis()+delay, period);
}
TimerTask
- Timer
에서 처리할 내용 (날짜/시간 가져와서 화면에 표시하기)
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
// 처리할 내용
}
};
Handler
- UI 작업은 백그라운드 스레드가 아닌 메인 스레드에서 처리해야하기 때문에 핸들러 사용하여 처리
final Handler handler = new Handler();
handler.post(new Runnable() {
@Override
public void run() {
// 처리할 내용
}
});
날짜/시간 표시
- Calendar
class 사용
- 요일은 getDisplayName(Calendar.DAY_OF_WEEK, Calendar.SHORT, Locale.KOREA)
- %02d
: 10 이하일 경우 앞에 0
붙도록
- month = month + 1;
: 월은 0 ~ 11 값을 반환. 1을 더해줘야 정상적으로 월 표시 가능 (2023.01.02 내용 추가)
지연 시간 계산
- 0 밀리초에 시작 되지 않아서 그런지 초가 미묘하게 빠르거나 느린 문제 발생. 이 부분 개선을 위한 코드
// 추가 : 0 millisecond 에 시작되도록 지연 시간 계산
Calendar startTick = Calendar.getInstance();
int delay = 1000 - startTick.get(Calendar.MILLISECOND);
if(delay == 1000){
delay = 0;
}
2023.04.17 내용 추가입니다.
지연 시간 계산 다시 제거
더 이상 해당 코드는 사용하고 있지 않지만, 지연 시간 계산이 필요없음을 알게 되었습니다.
(이유는 모르겠지만 Kotlin에서는 지연 시간 계산으로도 시간이 맞지 않아서 다른 방법을 찾아보게 됐습니다.)
기존:
1초(1000ms)마다 한 번씩 호출하게 되면, 호출 시점이 0ms가 아닐 경우 화면 갱신 시간은 계속 틀어진 채입니다.
변경:
사용자가 인식하지 못할 정도의 period로 자주 호출하여 갱신하면(예: 1000/30), 호출 시점이 0ms가 아니라도 잦은 갱신으로 자연스럽게 시간이 맞아떨어집니다.
변경 소스:
timer.scheduleAtFixedRate(timerTask, 0, 1000/30);
/* // 지연 시간 필요없음, 1초마다 호출이 아닌 (1000/30)초마다 호출
// 추가 : 0 millisecond 에 시작되도록 지연 시간 계산
Calendar startTick = Calendar.getInstance();
int delay = 1000 - startTick.get(Calendar.MILLISECOND);
if(delay == 1000){
delay = 0;
}
// 함수가 실행하면서 생긴 지연 시간을 무시
timer.scheduleAtFixedRate(timerTask, delay, 1000);
// 수정 전 : 선행 작업(가비지 컬렉션 등)으로 지연이 발생할 수 있음
//timer.schedule(timerTask, 0, 1000); */
'냐냐한 Dev Study > Android' 카테고리의 다른 글
[학습] 레모네이드 앱 프로젝트 (Android,Kotlin) (4) | 2023.01.10 |
---|---|
[학습] 주사위 굴리기 Android 앱 만들기 (Kotlin) (0) | 2023.01.09 |
[학습] 생일 축하 메세지 표시하는 간단 Android 앱 만들기 (Kotlin) (0) | 2023.01.06 |
[학습] Kotlin으로 Hello World + 생일 축하 메세지 작성 (0) | 2023.01.05 |
[학습] Android Basics in Kotlin 과정 소개 (0) | 2023.01.04 |