Android Wear 타이머 개발
본 고 는 우리 가 개발 하고 자 하 는 이 앱 의 용 도 를 장황 하 게 설명 하지 않 을 것 이다.왜냐하면 우 리 는 이전의 시리즈 글 에서 이미 깊이 이 해 했 기 때문이다.이렇게 말 하면 이것 은 타 이 밍 애플 리 케 이 션 으로 경기 가 시 작 될 때 실행 을 시작 하고 경기 과정 에서 일시 정지(정지)할 수 있 으 며 45 분 이 지나 면 진동 알림 이 있 고 경기 가 45 분 후에 도 알림 이 있 습 니 다.
시작 하기 전에 코드 를 직접 올 리 는 것 이 아니 라 우리 가 왜 이 앱 을 다시 써 야 하 는 지 볼 필요 가 있다.스마트 시 계 는 수 정 된 안 드 로 이 드 1.6 시스템 을 사용 하기 때문에 안 드 로 이 드 1.6 을 실행 하 는 핸드폰 과 구조 가 비슷 하기 때문에 우리 의 앱 은 하나의 Activity 를 바탕 으로 우리 의 모든 작업 이 이 Activity 에서 실 행 됩 니 다.스마트 워 치 개발 을 배우 기 전에 우 리 는 이전의 디자인 이 안 드 로 이 드 웨 어 에 적용 되 지 않 았 다 는 것 을 잘 알 아야 한다.비록 이것 도 Activity 를 지원 하지만 안 드 로 이 드 웨 어 에서 의 작업 방식 은 다르다.휴대 전화 나 태 블 릿 에서 하나의 액 티 비 티 가 sleep 상태 에서 깨 어 난 상태 로 돌아 가면 액 티 비 티 는 다시 깨 어 나 지만 Wear 에 서 는 그렇지 않다.시간 이 지나 면 Wear 장치 가 sleep 에 들 어가 지만 장치 가 깨 어 난 후 sleep 상태 에 있 는 Activity 는 다시 깨 어 나 지 않 는 다.
우선 이 문 제 는 저 를 매우 놀 라 게 했 습 니 다.저 는 Activity 에 이런 제한 이 생 긴 후에 도 실 용적 인 앱 을 개발 할 수 있 는 지 알 고 싶 었 습 니 다.나중에 야 이 문 제 는 완전히 걱정 이 많다 는 것 을 알 게 되 었 다.나 는 실 용적 인 앱 을 개발 하 는 것 도 간단 하 다 는 것 을 알 게 되 었 다.우 리 는 우리 의 소프트웨어 디자인 모델 을 바 꾸 어 안 드 로 이 드 Wear 의 체계 구조 에 더욱 부합 시 켜 야 한다.핸드폰 으로 보 는 것 이 아니 라 안 드 로 이 드 Wear 의 체계 구조 에 더욱 부합 하도록 해 야 한다.
여기 서 우리 가 고려 해 야 할 가장 기본 적 인 문 제 는 이 시간 계산 프로그램 이 계속 실행 되 는 서 비 스 를 바탕 으로 시간 을 기록 해 야 한 다 는 것 이다.그러나 장기 적 으로 운영 되 는 서 비 스 는 전기 가 소모 되 기 때문에 좋 은 방안 이 아니다.여기 서 우리 가 언급 한 기록 시간 이라는 키 워드 는 즉,우 리 는 정말 장시간 실행 되 는 서 비 스 를 실현 할 필요 가 없다.사용자 가 볼 필요 가 있 을 때 우 리 는 메 시 지 를 업데이트 할 수 있 으 면 된다.대부분의 시간 동안 사용 자 는 경기 가 중단 되 거나 미 드 필 더 가 끝나 갈 때 만 더 자세 한 정 보 를 표시 해 야 한다.그래서 대부분의 시간 동안 우 리 는 분 까지 만 정확하게 표시 하면 되 고 사용자 가 필요 할 때 만 초 까지 정확 하 다.
우리 가 이 방법 을 실현 하려 는 기본 적 인 방법 은 AlarmManager 를 사용 하여 매 분 마다 업데이트 알림 이 벤트 를 터치 하여 분 디 스 플레이 를 업데이트 하 는 것 이다.이 알림 이 벤트 는 초 까지 정확 한 Activity 를 표시 하지만 사용자 가 화면 을 미 끄 러 뜨 릴 때 만 전체 알림 을 표시 합 니 다.이런 방식 을 통 해 우 리 는 반드시 표시 해 야 할 때 만 메 시 지 를 업데이트 할 수 있 기 때문에 대부분의 장치 에 있어 서 1 분 에 한 번 씩 메 시 지 를 업데이트 하 는 것 이 서 비 스 를 계속 실행 하 는 것 보다 전 기 를 절약 할 수 있다.
다음 그림 은 이 점 을 충분히 증명 하고 있 습 니 다.먼저 알림 을 열 어야 합 니 다.그러면 초 까지 정확하게 표시 할 수 있 습 니 다.
그러나 정보 가 표시 되 거나 장치 가 휴면 할 때 우 리 는 분 까지 만 정확하게 표시 하면 된다.
한 가지 설명 이 필요 한 것 은 이 앱 의 이름 이 바 뀌 었 다 는 것 이다.기 존 에는 I'm Watch 버 전에 서'Footy Timer'라 고 불 렸 는데,지금 은'Match Timer'로 바 뀌 었 다.음성 으로 앱 을 시작 할 때 Google 의 음성 인식 은'Footy'라 는 단어 에 민감 하지 않 기 때문에'ok Google,start Footy Timer'라 는 명령 으로 앱 을 시작 할 수 없고'ok Google,start Match Timer'를 사용 하면 사용 할 수 있 습 니 다.
마지막 으로 이 글 은 코드 가 없어 서 죄 송 하지만 이 시 리 즈 는 조금 바 뀔 수 있 습 니 다.예전 에 저 는 모든 글 의 끝 에 글 과 관련 된 코드 세그먼트 를 첨부 했 습 니 다.이것 은 안심 하 세 요.그 후의 글 은 이렇게 될 것 입 니 다.이것 은 일련의 기술 문장 이 아니 라 기능 이 완 선 된 App 이기 때문에 다음 글 에는 코드 예제 와 주석 이 포함 되 어 있 고 본 시리즈 글 이 끝 날 때 전체 프로젝트 의 소스 코드 를 첨부 할 것 입 니 다.
Match Timer 는 Google Play 에서 찾 을 수 있 습 니 다https://play.google.com/store/apps/details?id=com.stylingandroid.matchtimer
안 드 로 이 드 웨 어 에서 이 타이머 앱 을 다시 쓰 는 이 유 를 설명 했다.
우 리 는 이 app 의 핵심 클래스 로 시작 합 니 다.이 클래스 는 타이머 의 상 태 를 제어 합 니 다.이 종 류 는 4 개의 long 형식의 변 수 를 포함 합 니 다.첫 번 째 는 타이머 가 시작 하 는 시간 을 대표 합 니 다.두 번 째 는 타이머 가 멈 추 는 시간 을 나타 낸다.세 번 째 대표 타 이 머 는 시계 가 멈 추 는 시간(현재 시계 가 멈 추 지 않 았 다 면 그것 도 0)이 고 네 번 째 대 표 는 모두 시계 가 멈 추 는 시간 입 니 다.이 네 개의 변 수 를 통 해 우 리 는 타이머 의 상 태 를 유지 할 수 있 고 계산 을 통 해 우리 가 보 여 줘 야 할 다른 정 보 를 얻 을 수 있다.이런 종류의 기본 기능 은 바로 이러한 변 수 를 조작 하기 위 한 것 이다.즉,타이머 의 이러한 상 태 를 유지 하기 위 한 것 이다.
public final class MatchTimer {
.
.
.
public static final int MINUTE_MILLIS = 60000;
private long start;
private long currentStoppage;
private long totalStoppages;
private long end;
.
.
.
public long getElapsed() {
if (isRunning()) {
return System.currentTimeMillis() - start;
}
if (end > 0) {
return end - start;
}
return 0;
}
public boolean isRunning() {
return start > 0 && end == 0;
}
public boolean isPaused() {
return currentStoppage > 0;
}
public int getElapsedMinutes() {
return (int) ((System.currentTimeMillis() - start) / MINUTE_MILLIS);
}
public long getTotalStoppages() {
long now = System.currentTimeMillis();
if (isPaused()) {
return totalStoppages + (now - currentStoppage);
}
return totalStoppages;
}
public long getPlayed() {
return getElapsed() - getTotalStoppages();
}
public long getStartTime() {
return start;
}
.
.
.
}
이것들 은 모두 기본 적 인 자바 코드 이 므 로 시간 이 걸 리 지 않 습 니 다.아래 의 함수 가 좀 더 고 급 스 러 워 서 타 이 머 를 조작 할 수 있 는 상태 입 니 다.
public final class MatchTimer {
.
.
.
public void start() {
if (end > 0) {
start = System.currentTimeMillis() - (end - start);
end = 0;
} else {
start = System.currentTimeMillis();
}
save();
}
public void stop() {
if (isPaused()) {
resume();
}
end = System.currentTimeMillis();
save();
}
public void pause() {
currentStoppage = System.currentTimeMillis();
save();
}
public void resume() {
totalStoppages += System.currentTimeMillis() - currentStoppage;
currentStoppage = 0L;
save();
}
public void reset() {
resetWithoutSave();
save();
}
private void resetWithoutSave() {
start = 0L;
currentStoppage = 0L;
totalStoppages = 0L;
end = 0L;
}
}
이것들 은 기본 적 인 자바 코드 이 니 말 할 필요 도 없다.save()방법 만 우 리 는 아직 보지 못 했 습 니 다.이것 은 클래스 의 마지막 에 쓴 것 입 니 다.이 함수 만 이 우리 가 이야기 할 가치 가 있 습 니 다.앞의 글 에서 우 리 는 깨 우기 메커니즘 에 관 한 문 제 를 토론 했다.우 리 는 긴 연결 이나 백 스테이지 서 비 스 를 유지 할 필요 가 없고 이 몇 개의 타이머 의 상 태 를 유지 하면 된다.저 희 는 Shared Preference 를 사용 하여 이 루어 집 니 다.
public final class MatchTimer implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final String KEY_START = "com.stylingandroid.matchtimer.KEY_START";
private static final String KEY_CURRENT_STOPPAGE = "com.stylingandroid.matchtimer.KEY_CURRENT_STOPPAGE";
private static final String KEY_TOTAL_STOPPAGES = "com.stylingandroid.matchtimer.KEY_TOTAL_STOPPAGES";
private static final String KEY_END = "com.stylingandroid.matchtimer.KEY_END";
private static final String PREFERENCES = "MatchTimer";
private final SharedPreferences preferences;
public static MatchTimer newInstance(Context context) {
SharedPreferences preferences = context.getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE);
long start = preferences.getLong(KEY_START, 0);
long currentStoppage = preferences.getLong(KEY_CURRENT_STOPPAGE, 0);
long totalStoppages = preferences.getLong(KEY_TOTAL_STOPPAGES, 0);
long end = preferences.getLong(KEY_END, 0);
return new MatchTimer(preferences, start, currentStoppage, totalStoppages, end);
}
private MatchTimer(SharedPreferences preferences, long start, long currentStoppage, long totalStoppages, long end) {
this.preferences = preferences;
this.start = start;
this.currentStoppage = currentStoppage;
this.totalStoppages = totalStoppages;
this.end = end;
}
public void save() {
preferences.edit()
.putLong(KEY_START, start)
.putLong(KEY_CURRENT_STOPPAGE, currentStoppage)
.putLong(KEY_TOTAL_STOPPAGES, totalStoppages)
.putLong(KEY_END, end)
.apply();
}
public void registerForUpdates() {
preferences.registerOnSharedPreferenceChangeListener(this);
}
public void unregisterForUpdates() {
preferences.unregisterOnSharedPreferenceChangeListener(this);
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
long value = sharedPreferences.getLong(key, 0L);
if (key.equals(KEY_START)) {
start = value;
} else if (key.equals(KEY_END)) {
end = value;
} else if (key.equals(KEY_CURRENT_STOPPAGE)) {
currentStoppage = value;
} else if (key.equals(KEY_TOTAL_STOPPAGES)) {
totalStoppages = value;
}
}
.
.
.
}
우리 에 게 필요 한 것 은 new Instance()방법 입 니 다.Shared Preference 에서 MatchTimer 인 스 턴 스 를 구성 하 는 것 입 니 다.우 리 는 save()방법 이 필요 합 니 다.현재 타이머 상 태 를 Shared Preference 에 저장 할 수 있 습 니 다.마지막 으로 우리 가 설명 하고 자 하 는 것 은 어느 부분 이 MatchTimer 대상 의 인용 을 가지 고 있 지만 다른 대상 이 타이머 의 상 태 를 바 꾸 었 다 면 이상 이 발생 할 수 있다 는 것 이다(다음 글 참조).그래서 저 희 는 Matchtimer 의 인 스 턴 스 를 등록 하고 취소 하 는 방법 도 제공 해 야 합 니 다.Shared preference 의 값 이 바 뀔 때 타이머 상태의 변 화 를 받 아야 합 니 다.
이제 우 리 는 기본 적 인 타 이 머 를 정 의 했 습 니 다.다음 글 은 타이머 의 상 태 를 어떻게 유지 하고 필요 할 때 이 상 태 를 깨 우 는 지 소개 합 니 다.
Match Timer 는 Google Play 에서 다운로드 할 수 있 습 니 다Match Timer
본 시리즈 의 몇 편의 글 에서 우 리 는 Android Wear 타이머 app 을 소개 하고 디자인 사고 와 app 의 구 조 를 분석 했다.본 고 는 어떻게 정시 에 프로그램 을 깨 워 사용자 에 게 알 리 는 지 설명 할 것 이다.
왜 백 스테이지 서 비 스 를 사용 하지 않 는 방식 이 계속 운행 되 는 지 에 대해 우 리 는 이미 설명 을 했다.이런 방식 은 전기 소모 가 매우 많다.따라서 우 리 는 반드시 정시 각성 메커니즘 이 있어 야 한다.우 리 는 AlarmManager 를 사용 하여 이 체 제 를 실현 하고 정기 적 으로 Intent 를 실행 한 후에 BroadcastReceiver 에 게 알 릴 수 있 습 니 다.IntentService 대신 BroadcastReceiver 를 선택 한 이 유 는 우리 가 실행 해 야 할 임 무 는 경량급 이 고 수명 주기 가 매우 짧 기 때문이다.BroadcastReceiver 를 사용 하면 임 무 를 수행 할 때마다 Service 의 전체 생명 주 기 를 겪 는 것 을 피 할 수 있 습 니 다.따라서 우리 같은 경량급 의 임무 에 있어 서 매우 적합 하 다.우리 가 수행 하 는 임 무 는 모두 밀리초 급 이다.
BroadcastReceiver 의 핵심 은 onReceiver 방법 입 니 다.다양한 이벤트 응답 을 설정 해 야 합 니 다.
public class MatchTimerReceiver extends BroadcastReceiver {
public static final int MINUTE_MILLIS = 60000;
private static final long DURATION = 45 * MINUTE_MILLIS;
private static final Intent UPDATE_INTENT = new Intent(ACTION_UPDATE);
private static final Intent ELAPSED_ALARM = new Intent(ACTION_ELAPSED_ALARM);
private static final Intent FULL_TIME_ALARM = new Intent(ACTION_FULL_TIME_ALARM);
private static final int REQUEST_UPDATE = 1;
private static final int REQUEST_ELAPSED = 2;
private static final int REQUEST_FULL_TIME = 3;
public static void setUpdate(Context context) {
context.sendBroadcast(UPDATE_INTENT);
}
.
.
.
private void reset(MatchTimer timer) {
timer.reset();
}
private void resume(Context context, MatchTimer timer) {
timer.resume();
long playedEnd = timer.getStartTime() + timer.getTotalStoppages() + DURATION;
if (playedEnd > System.currentTimeMillis()) {
setAlarm(context, REQUEST_FULL_TIME, FULL_TIME_ALARM, playedEnd);
}
}
private void pause(Context context, MatchTimer timer) {
timer.pause();
cancelAlarm(context, REQUEST_FULL_TIME, FULL_TIME_ALARM);
long elapsedEnd = timer.getStartTime() + DURATION;
if (!isAlarmSet(context, REQUEST_ELAPSED, ELAPSED_ALARM) && elapsedEnd > System.currentTimeMillis()) {
setAlarm(context, REQUEST_ELAPSED, ELAPSED_ALARM, elapsedEnd);
}
}
private void stop(Context context, MatchTimer timer) {
timer.stop();
cancelAlarm(context, REQUEST_UPDATE, UPDATE_INTENT);
cancelAlarm(context, REQUEST_ELAPSED, ELAPSED_ALARM);
cancelAlarm(context, REQUEST_FULL_TIME, FULL_TIME_ALARM);
}
private void start(Context context, MatchTimer timer) {
timer.start();
long elapsedEnd = timer.getStartTime() + DURATION;
setRepeatingAlarm(context, REQUEST_UPDATE, UPDATE_INTENT);
if (timer.getTotalStoppages() > 0 && !timer.isPaused()) {
long playedEnd = timer.getStartTime() + timer.getTotalStoppages() + DURATION;
if (playedEnd > System.currentTimeMillis()) {
setAlarm(context, REQUEST_FULL_TIME, FULL_TIME_ALARM, playedEnd);
}
if (elapsedEnd > System.currentTimeMillis()) {
setAlarm(context, REQUEST_ELAPSED, ELAPSED_ALARM, elapsedEnd);
}
} else {
if (elapsedEnd > System.currentTimeMillis()) {
setAlarm(context, REQUEST_FULL_TIME, FULL_TIME_ALARM, elapsedEnd);
}
}
}
.
.
.
}
코드 는 여전히 매우 직관 적 이 고 이해 하기 쉽다.먼저 MatchTimer 대상(Shared Preference 에서 데 이 터 를 읽 기)을 예화 한 다음 해당 하 는 이벤트 처리 Handler 에 각각 전달 합 니 다.이후 동작 이 발생 할 때 까지 기 다 렸 다가 Notification 을 업데이트 합 니 다.여기 서 8 개의 이벤트 동작 을 처리 하 는데 그 중에서 5 개 는 타이머 의 상태(START,STOP,PAUSE,RESUME,RESET)를 제어 하 는 것 을 책임 집 니 다.하 나 는 Notification 업 데 이 트 를 담당 하고 나머지 두 개 는 45 분 까지 깨 운 후 진동 알림 을 담당한다.
우 리 는 먼저 이 몇 가지 통제 상태 부터 시작한다.
public class MatchTimerReceiver extends BroadcastReceiver {
public static final int MINUTE_MILLIS = 60000;
private static final long DURATION = 45 * MINUTE_MILLIS;
private static final Intent UPDATE_INTENT = new Intent(ACTION_UPDATE);
private static final Intent ELAPSED_ALARM = new Intent(ACTION_ELAPSED_ALARM);
private static final Intent FULL_TIME_ALARM = new Intent(ACTION_FULL_TIME_ALARM);
private static final int REQUEST_UPDATE = 1;
private static final int REQUEST_ELAPSED = 2;
private static final int REQUEST_FULL_TIME = 3;
public static void setUpdate(Context context) {
context.sendBroadcast(UPDATE_INTENT);
}
.
.
.
private void reset(MatchTimer timer) {
timer.reset();
}
private void resume(Context context, MatchTimer timer) {
timer.resume();
long playedEnd = timer.getStartTime() + timer.getTotalStoppages() + DURATION;
if (playedEnd > System.currentTimeMillis()) {
setAlarm(context, REQUEST_FULL_TIME, FULL_TIME_ALARM, playedEnd);
}
}
private void pause(Context context, MatchTimer timer) {
timer.pause();
cancelAlarm(context, REQUEST_FULL_TIME, FULL_TIME_ALARM);
long elapsedEnd = timer.getStartTime() + DURATION;
if (!isAlarmSet(context, REQUEST_ELAPSED, ELAPSED_ALARM) && elapsedEnd > System.currentTimeMillis()) {
setAlarm(context, REQUEST_ELAPSED, ELAPSED_ALARM, elapsedEnd);
}
}
private void stop(Context context, MatchTimer timer) {
timer.stop();
cancelAlarm(context, REQUEST_UPDATE, UPDATE_INTENT);
cancelAlarm(context, REQUEST_ELAPSED, ELAPSED_ALARM);
cancelAlarm(context, REQUEST_FULL_TIME, FULL_TIME_ALARM);
}
private void start(Context context, MatchTimer timer) {
timer.start();
long elapsedEnd = timer.getStartTime() + DURATION;
setRepeatingAlarm(context, REQUEST_UPDATE, UPDATE_INTENT);
if (timer.getTotalStoppages() > 0 && !timer.isPaused()) {
long playedEnd = timer.getStartTime() + timer.getTotalStoppages() + DURATION;
if (playedEnd > System.currentTimeMillis()) {
setAlarm(context, REQUEST_FULL_TIME, FULL_TIME_ALARM, playedEnd);
}
if (elapsedEnd > System.currentTimeMillis()) {
setAlarm(context, REQUEST_ELAPSED, ELAPSED_ALARM, elapsedEnd);
}
} else {
if (elapsedEnd > System.currentTimeMillis()) {
setAlarm(context, REQUEST_FULL_TIME, FULL_TIME_ALARM, elapsedEnd);
}
}
}
.
.
.
}
이 방법 들 은 주로 두 가지 기능 이 있 습 니 다.먼저 MatchTimer 의 상 태 를 설정 한 다음 에 시간 알림 알 람 을 설정 하고 파 라 메 터 를 바 꾸 면 알 람 을 재생 할 수 있 습 니 다.이 기능 은 setUpdate()라 는 도구 방법 으로 도 봉 할 수 있다.이렇게 하면 외부 에서 도 타이머 의 업 데 이 트 를 촉발 할 수 있다.우 리 는 표준 알 람 관리자 의 방법 으로 알 람 을 설정 합 니 다.
public class MatchTimerReceiver extends BroadcastReceiver {
.
.
.
public static final int MINUTE_MILLIS = 60000;
.
.
.
private void setRepeatingAlarm(Context context, int requestCode, Intent intent) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), MINUTE_MILLIS, pendingIntent);
}
private boolean isAlarmSet(Context context, int requestCode, Intent intent) {
return PendingIntent.getBroadcast(context, requestCode, intent, PendingIntent.FLAG_NO_CREATE) != null;
}
private void setAlarm(Context context, int requestCode, Intent intent, long time) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent);
}
private void cancelAlarm(Context context, int requestCode, Intent intent) {
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, requestCode, intent, PendingIntent.FLAG_NO_CREATE);
if (pendingIntent != null) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
pendingIntent.cancel();
}
}
.
.
.
}
여기 서 논의 할 만 한 것 은 set Repeating Alarm()이라는 방법 이다.Wear 에 서 는 실현 방식 이 좀 다 르 기 때문이다.Start 이벤트 에서 1 초 에 한 번 씩 알 람 을 울 려 Notification 동작 을 업데이트 하기 때문에 구체 적 으로 몇 분 이 지 났 는 지 기록 해 야 합 니 다.일반적으로 우 리 는 60 초 에 한 번 씩 이 동작 을 촉발 하지만 Wear 에 서 는 이렇게 할 수 없다.그 이 유 는 설비 가 깨 어 있 을 때 이렇게 할 수 있 지만 설비 가 수면 상태 에 들 어가 면 다음 분 의 경계 치 를 다시 계산 해 야 하기 때문이다.위 젯 을 비동기 로 업데이트 하고 장 치 는 분당 한 번 만 깨 워 야 합 니 다.1 분 이 끝 난 후 타이머 가 상 태 를 업데이트 해 야 할 때 작 동 합 니 다.우리 의 타이머 애플 리 케 이 션 에 있어 서 표시 되 는 분 수 는 실제 시간 보다 1 분 이 적다.그러나 디 스 플레이 분 은 매우 실시 간 으로 요구 되 지 않 습 니 다.(단,초 수 를 표시 할 때 매우 정확 해 야 합 니 다)그래서 우 리 는 이렇게 조작 할 수 있 습 니 다.
완전한 alarm Handler 는 이렇게 진동 서 비 스 를 사용 합 니 다.
public class MatchTimerReceiver extends BroadcastReceiver {
.
.
.
private static final long[] ELAPSED_PATTERN = {0, 500, 250, 500, 250, 500};
private static final long[] FULL_TIME_PATTERN = {0, 1000, 500, 1000, 500, 1000};
private void elapsedAlarm(Context context) {
Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(ELAPSED_PATTERN, -1);
}
private void fullTimeAlarm(Context context) {
Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(FULL_TIME_PATTERN, -1);
}
.
.
.
}
마지막 으로,우 리 는 이 방법 을 통 해 Notification 을 구성 하여 사용자 에 게 보 여 줍 니 다.
public class MatchTimerReceiver extends BroadcastReceiver {
public static final int NOTIFICATION_ID = 1;
.
.
.
private void updateNotification(Context context, MatchTimer timer) {
NotificationBuilder builder = new NotificationBuilder(context, timer);
Notification notification = builder.buildNotification();
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
notificationManager.notify(NOTIFICATION_ID, notification);
}
}
Notification 은 Wear 타이머 의 중요 한 부분 입 니 다.이 Notification 알림 을 구성 하기 위해 서 는 사용자 정의 클래스 가 필요 합 니 다.다음 글 은 타이머 app 에서 Notification 을 사용 하 는 방법 을 알려 드 리 겠 습 니 다.Match Timer 는 Google Play 에서 다운로드 할 수 있 습 니 다Match Timer
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Bitrise에서 배포 어플리케이션 설정 테스트하기이 글은 Bitrise 광고 달력의 23일째 글입니다. 자체 또는 당사 등에서 Bitrise 구축 서비스를 사용합니다. 그나저나 며칠 전 Bitrise User Group Meetup #3에서 아래 슬라이드를 발표했...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.