카드에서 주기적인 업데이트 표시

시간이 지남에 따라 변경되는 콘텐츠를 포함하는 카드를 만듭니다.

타임라인 사용

타임라인은 하나 이상의 TimelineEntry 인스턴스로 구성됩니다. 각 인스턴스는 특정 시간 간격 동안 표시되는 레이아웃을 포함합니다. 모든 카드에는 타임라인이 필요합니다.

카드 타임라인 다이어그램

단일 항목 카드

카드는 하나의 TimelineEntry로 설명할 수 있는 경우가 많습니다. 레이아웃은 고정되어 있고 레이아웃 내부의 정보만 변경됩니다. 예를 들어, 하루의 피트니스 진행 상황을 보여주는 카드는 다른 값을 표시하도록 레이아웃을 조정해도 항상 동일한 진행 상황 레이아웃을 표시합니다. 이때 콘텐츠가 언제 변경될지 미리 알 수 없습니다.

단일 TimelineEntry를 갖는 카드의 예를 참고하세요.

Kotlin

override fun onTileRequest(
    requestParams: TileRequest
): ListenableFuture<Tile> {
    val tile = Tile.Builder()
        .setResourcesVersion(RESOURCES_VERSION)

        // We add a single timeline entry when our layout is fixed, and
        // we don't know in advance when its contents might change.
        .setTileTimeline(
            Timeline.fromLayoutElement(...)
        ).build()
    return Futures.immediateFuture(tile)
}

Java

@Override
protected ListenableFuture<Tile> onTileRequest(
       @NonNull TileRequest requestParams
) {
   Tile tile = new Tile.Builder()
       .setResourcesVersion(RESOURCES_VERSION)
       
       // We add a single timeline entry when our layout is fixed, and
       // we don't know in advance when its contents might change.
       .setTileTimeline(
            Timeline.fromLayoutElement(...)
       ).build();
   return Futures.immediateFuture(tile);
}

기한이 있는 타임라인 항목

TimelineEntry는 선택적으로 유효 기간을 정의할 수 있으며 이에 따라 앱이 새 카드를 푸시하지 않아도 카드가 알려진 시간에 레이아웃을 변경할 수 있습니다.

표준 예로 타임라인에 향후 이벤트 목록이 포함된 일정 카드를 들 수 있습니다. 각 향후 이벤트에는 이벤트가 표시되는 시점을 나타내는 유효 기간이 포함됩니다.

Tiles API를 사용하면 유효 기간을 중복하여 지정할 수 있습니다. 유효 기간이 중복 지정된 경우 남은 시간이 가장 짧은 화면이 표시됩니다. 한 번에 하나의 이벤트만 표시됩니다.

개발자가 대체 항목 기본값을 제공할 수 있습니다. 예를 들어, 일정 카드에 유효 기간이 무한한 다른 카드를 갖는 경우 이 카드는 다음 코드 샘플과 같이 다른 유효한 타임라인 항목이 없을 때 사용됩니다.

Kotlin

public override fun onTileRequest(
    requestParams: TileRequest
): ListenableFuture<Tile> {
    val timeline = Timeline.Builder()

    // Add fallback "no meetings" entry
    // Use the version of TimelineEntry that's in androidx.wear.protolayout.
    timeline.addTimelineEntry(TimelineEntry.Builder()
        .setLayout(getNoMeetingsLayout())
        .build()
    )

    // Retrieve a list of scheduled meetings
    val meetings = MeetingsRepo.getMeetings()
    // Add a timeline entry for each meeting
    meetings.forEach { meeting ->
        timeline.addTimelineEntry(TimelineEntry.Builder()
            .setLayout(getMeetingLayout(meeting))
            .setValidity(
                // The tile should disappear when the meeting begins
                // Use the version of TimeInterval that's in
                // androidx.wear.protolayout.
                TimeInterval.Builder()
                    .setEndMillis(meeting.dateTimeMillis).build()
            ).build()
        )
    }

    val tile = Tile.Builder()
        .setResourcesVersion(RESOURCES_VERSION)
        .setTileTimeline(timeline.build())
        .build()
    return Futures.immediateFuture(tile)
}

Java

@Override
protected ListenableFuture<Tile> onTileRequest(
       @NonNull RequestBuilders.TileRequest requestParams
) {
   Timeline.Builder timeline = new Timeline.Builder();
   // Add fallback "no meetings" entry
   // Use the version of TimelineEntry that's in androidx.wear.protolayout.
   timeline.addTimelineEntry(new TimelineEntry.Builder().setLayout(getNoMeetingsLayout()).build());
   // Retrieve a list of scheduled meetings
   List<Meeting> meetings = MeetingsRepo.getMeetings();
   // Add a timeline entry for each meeting
   for(Meeting meeting : meetings) {
        timeline.addTimelineEntry(new TimelineEntry.Builder()
            .setLayout(getMeetingLayout(meeting))
            .setValidity(
                // The tile should disappear when the meeting begins
                // Use the version of TimeInterval that's in
                // androidx.wear.protolayout.
                new TimeInterval.builder()
                    .setEndMillis(meeting.getDateTimeMillis()).build()
            ).build()
        );
    }

    Tile tile = new Tile.Builder()
        .setResourcesVersion(RESOURCES_VERSION)
        .setTileTimeline(timeline.build())
        .build();
    return Futures.immediateFuture(tile);
}

카드 새로고침

카드에 표시된 정보는 일정 시간이 지나면 만료될 수 있습니다. 예를 들어, 하루 종일 동일한 온도를 표시하는 날씨 카드는 정확하지 않습니다.

만료되는 데이터를 처리하려면 카드 생성 시점에 카드의 유효 기간을 지정하는 새로고침 간격을 설정합니다. 날씨 카드의 경우 다음 코드 샘플과 같이 1시간에 한 번 콘텐츠를 업데이트할 수 있습니다.

Kotlin

override fun onTileRequest(requestParams: RequestBuilders.TileRequest) =
    Futures.immediateFuture(Tile.Builder()
        .setResourcesVersion(RESOURCES_VERSION)
        .setFreshnessIntervalMillis(60 * 60 * 1000) // 60 minutes
        .setTileTimeline(Timeline.fromLayoutElement(
            getWeatherLayout())
        ).build()
    )

Java

@Override
protected ListenableFuture<Tile> onTileRequest(
       @NonNull TileRequest requestParams
) {
    return Futures.immediateFuture(new Tile.Builder()
        .setResourcesVersion(RESOURCES_VERSION)
        .setFreshnessIntervalMillis(60 * 60 * 1000) // 60 minutes
        .setTimeline(Timeline.fromLayoutElement(
            getWeatherLayout())
        ).build());
}

새로고침 간격을 설정하면 시스템은 그 시간이 종료되면 곧 onTileRequest()를 호출합니다. 새로고침 간격을 설정하지 않으면 시스템이 onTileRequest()를 호출하지 않습니다.

카드가 외부 이벤트로 인해 만료되는 경우도 있습니다. 예를 들어, 사용자가 캘린더에서 회의를 삭제했는데 카드가 새로고침되지 않았다면 계속해서 삭제된 회의가 표시될 것입니다. 이 경우 다음 코드 샘플과 같이 애플리케이션 코드의 아무 데서나 새로고침을 요청하면 됩니다.

Kotlin

fun eventDeletedCallback() {
     TileService.getUpdater(context)
             .requestUpdate(MyTileService::class.java)
}

Java

public void eventDeletedCallback() {
   TileService.getUpdater(context)
           .requestUpdate(MyTileService.class);
}

업데이트 워크플로 선택

다음 권장사항에 따라 카드 업데이트를 구성할 방법을 정하세요.

  • 업데이트를 예측할 수 있는 경우(예: 사용자 캘린더의 다음 이벤트 업데이트인 경우) 타임라인을 사용합니다.
  • 플랫폼 데이터를 가져올 때는 시스템에서 자동으로 데이터를 업데이트하도록 데이터 결합을 사용합니다.
  • 짧은 시간 내에 기기에서 업데이트를 계산할 수 있는 경우(예: 일출 카드에서 이미지의 위치 업데이트) onTileRequest()를 사용합니다.

    이 기능은 모든 이미지를 미리 생성해야 하는 경우에 특히 유용합니다. 나중에 새 이미지를 생성해야 하는 경우에는 setFreshnessIntervalMillis()를 호출합니다.

  • 날씨 데이터 폴링과 같이 보다 집중적인 백그라운드 작업을 하는 경우에는 WorkManager를 사용하고 카드로 업데이트를 푸시합니다.

  • 업데이트가 외부 이벤트에 대한 응답인 경우(예: 조명이 켜짐, 이메일을 수신함, 메모가 업데이트됨) Firebase 클라우드 메시징(FCM) 메시지를 보내서 앱을 다시 활성화한 다음 카드로 업데이트를 푸시합니다.

  • 카드 데이터 동기화 프로세스에 비용이 많이 드는 경우에는 다음 단계를 따르세요.

    1. 데이터 동기화를 예약합니다.
    2. 1~2초 타이머를 시작합니다.
    3. 시간이 다 되기 전에 원격 데이터 소스에서 업데이트를 받은 경우 데이터 동기화로부터 업데이트된 값을 표시합니다. 그 밖의 경우에는 캐시된 로컬 값을 표시합니다.