Android Wear 타이머 개발

21498 단어 AndroidWear타이머
2013 년 12 월 에는 축구 경기 에서 정지 시간 을 기록 할 수 있 도록 스마트 워 치 를 개발 하 는 앱 을 소개 하 는 시리즈 글 이 있 었 던 것 으로 기억 된다.안 드 로 이 드 웨 어가 출시 되면 서 웨 어 러 블 기기 에서 이런 앱 을 개발 하 는 것 은 좋 은 생각 이지 만 현재 안 드 로 이 드 웨 어 구조 로 는 어 려 운 것 같다.그래서 이 시 리 즈 는 이 앱 을 다시 써 서 안 드 로 이 드 웨 어의 세계 로 안내 합 니 다.
본 고 는 우리 가 개발 하고 자 하 는 이 앱 의 용 도 를 장황 하 게 설명 하지 않 을 것 이다.왜냐하면 우 리 는 이전의 시리즈 글 에서 이미 깊이 이 해 했 기 때문이다.이렇게 말 하면 이것 은 타 이 밍 애플 리 케 이 션 으로 경기 가 시 작 될 때 실행 을 시작 하고 경기 과정 에서 일시 정지(정지)할 수 있 으 며 45 분 이 지나 면 진동 알림 이 있 고 경기 가 45 분 후에 도 알림 이 있 습 니 다.
시작 하기 전에 코드 를 직접 올 리 는 것 이 아니 라 우리 가 왜 이 앱 을 다시 써 야 하 는 지 볼 필요 가 있다.스마트 시 계 는 수 정 된 안 드 로 이 드 1.6 시스템 을 사용 하기 때문에 안 드 로 이 드 1.6 을 실행 하 는 핸드폰 과 구조 가 비슷 하기 때문에 우리 의 앱 은 하나의 Activity 를 바탕 으로 우리 의 모든 작업 이 이 Activity 에서 실 행 됩 니 다.스마트 워 치 개발 을 배우 기 전에 우 리 는 이전의 디자인 이 안 드 로 이 드 웨 어 에 적용 되 지 않 았 다 는 것 을 잘 알 아야 한다.비록 이것 도 Activity 를 지원 하지만 안 드 로 이 드 웨 어 에서 의 작업 방식 은 다르다.휴대 전화 나 태 블 릿 에서 하나의 액 티 비 티 가 sleep 상태 에서 깨 어 난 상태 로 돌아 가면 액 티 비 티 는 다시 깨 어 나 지만 Wear 에 서 는 그렇지 않다.시간 이 지나 면 Wear 장치 가 sleep 에 들 어가 지만 장치 가 깨 어 난 후 sleep 상태 에 있 는 Activity 는 다시 깨 어 나 지 않 는 다.
우선 이 문 제 는 저 를 매우 놀 라 게 했 습 니 다.저 는 Activity 에 이런 제한 이 생 긴 후에 도 실 용적 인 앱 을 개발 할 수 있 는 지 알 고 싶 었 습 니 다.나중에 야 이 문 제 는 완전히 걱정 이 많다 는 것 을 알 게 되 었 다.나 는 실 용적 인 앱 을 개발 하 는 것 도 간단 하 다 는 것 을 알 게 되 었 다.우 리 는 우리 의 소프트웨어 디자인 모델 을 바 꾸 어 안 드 로 이 드 Wear 의 체계 구조 에 더욱 부합 시 켜 야 한다.핸드폰 으로 보 는 것 이 아니 라 안 드 로 이 드 Wear 의 체계 구조 에 더욱 부합 하도록 해 야 한다.
여기 서 우리 가 고려 해 야 할 가장 기본 적 인 문 제 는 이 시간 계산 프로그램 이 계속 실행 되 는 서 비 스 를 바탕 으로 시간 을 기록 해 야 한 다 는 것 이다.그러나 장기 적 으로 운영 되 는 서 비 스 는 전기 가 소모 되 기 때문에 좋 은 방안 이 아니다.여기 서 우리 가 언급 한 기록 시간 이라는 키 워드 는 즉,우 리 는 정말 장시간 실행 되 는 서 비 스 를 실현 할 필요 가 없다.사용자 가 볼 필요 가 있 을 때 우 리 는 메 시 지 를 업데이트 할 수 있 으 면 된다.대부분의 시간 동안 사용 자 는 경기 가 중단 되 거나 미 드 필 더 가 끝나 갈 때 만 더 자세 한 정 보 를 표시 해 야 한다.그래서 대부분의 시간 동안 우 리 는 분 까지 만 정확하게 표시 하면 되 고 사용자 가 필요 할 때 만 초 까지 정확 하 다.
우리 가 이 방법 을 실현 하려 는 기본 적 인 방법 은 AlarmManager 를 사용 하여 매 분 마다 업데이트 알림 이 벤트 를 터치 하여 분 디 스 플레이 를 업데이트 하 는 것 이다.이 알림 이 벤트 는 초 까지 정확 한 Activity 를 표시 하지만 사용자 가 화면 을 미 끄 러 뜨 릴 때 만 전체 알림 을 표시 합 니 다.이런 방식 을 통 해 우 리 는 반드시 표시 해 야 할 때 만 메 시 지 를 업데이트 할 수 있 기 때문에 대부분의 장치 에 있어 서 1 분 에 한 번 씩 메 시 지 를 업데이트 하 는 것 이 서 비 스 를 계속 실행 하 는 것 보다 전 기 를 절약 할 수 있다.
다음 그림 은 이 점 을 충분히 증명 하고 있 습 니 다.먼저 알림 을 열 어야 합 니 다.그러면 초 까지 정확하게 표시 할 수 있 습 니 다.
matchtimer
그러나 정보 가 표시 되 거나 장치 가 휴면 할 때 우 리 는 분 까지 만 정확하게 표시 하면 된다.
matchtimer_notification
matchtimer_sleep
한 가지 설명 이 필요 한 것 은 이 앱 의 이름 이 바 뀌 었 다 는 것 이다.기 존 에는 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

좋은 웹페이지 즐겨찾기