عرض التحديثات الدورية في المربّعات

إنشاء شاشات تتضمن محتوى يتغير بمرور الوقت.

العمل باستخدام الجداول الزمنية

يتألف المخطط الزمني من مثيل واحد أو أكثر [TimelineEntry][1] يحتوي كلٌ منها على تنسيق يتم عرضه خلال فترة زمنية محدّدة. يجب تحديد مخطط زمني لجميع المربّعات.

رسم بياني للمخطط الزمني للمربّعات

مربّعات ذات إدخال واحد

ويمكن غالبًا وصف المربّع باستخدام علامة 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 لفترات صلاحية متداخلة، حيث يتم عرض الشاشة التي تظهر أقصر فترة زمنية متبقية. يتم عرض حدث واحد فقط في كل مرة.

يمكن للمطوّرين توفير إدخال احتياطي تلقائي. على سبيل المثال، يمكن أن يحتوي مربع جدول الأعمال على مربع يحتوي على فترة صلاحية غير محدودة، ويتم استخدامه في حال عدم صلاحية إدخال آخر للجدول الزمني، كما هو موضح في نموذج الرمز البرمجي التالي:

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);
}

إعادة تحميل مربّع

قد تنتهي صلاحية المعلومات المعروضة على المربّع بعد مرور بعض الوقت. على سبيل المثال، فإن مربع الطقس الذي يعرض نفس درجة الحرارة على مدار اليوم ليس دقيقًا.

للتعامل مع البيانات المنتهية الصلاحية، عليك ضبط فاصل زمني للحداثة عند إنشاء مربّع، لتحديد مدة صلاحية هذا المربّع. في مثال مربع الطقس، يمكنك تحديث المحتوى كل ساعة، كما هو موضح في عينة التعليمات البرمجية التالية:

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()][2] بعد وقت قصير من انتهاء ذلك الفاصل. وإذا لم يتم ضبط فاصل زمني للتحديث، لن يستدعي النظام onTileRequest().

يمكن أن تنتهي صلاحية مربّع أيضًا بسبب حدث خارجي. على سبيل المثال، قد يُزيل أحد المستخدمين اجتماعًا من تقويمه، وإذا لم يتم إعادة تحميل القسم، سيظل يعرض المربّع هذا الاجتماع المحذوف. في هذه الحالة، اطلب التحديث من أي مكان في رمز تطبيقك، كما هو موضّح في نموذج الرمز التالي:

Kotlin

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

Java

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

اختيار سير عمل التحديث

يمكنك اتّباع أفضل الممارسات التالية لتحديد كيفية ضبط تعديلات المربّعات:

  • إذا كان من الممكن توقُّع التحديث، على سبيل المثال، إذا كان الحدث للحدث التالي في تقويم المستخدم، يمكنك استخدام مخطط زمني.
  • عند استرجاع بيانات النظام الأساسي، استخدِم ربط البيانات حتى يحدّث النظام البيانات تلقائيًا.
  • إذا كان من الممكن احتساب التعديل على الجهاز خلال فترة زمنية قصيرة، مثل تعديل موضع الصورة على مربّع شروق الشمس، استخدِم [onTileRequest()][2].

    ويكون ذلك مفيدًا بشكل خاص عندما تحتاج إلى إنشاء جميع الصور في وقت مبكر. إذا أردت إنشاء صورة جديدة في المستقبل، يمكنك طلب [setFreshnessIntervalMillis()][3].

  • إذا كنت تكرّر مهامًا مكثّفة في الخلفية، مثل إجراء استطلاع للحصول على بيانات الطقس، استخدِم [WorkManager][4] وأدخِل التعديلات على المربّع.

  • إذا كان التحديث استجابةً لحدث خارجي، مثل تشغيل الأضواء أو تلقّي رسالة إلكترونية أو تعديل ملاحظة، أرسِل رسالة [خدمة المراسلة عبر السحابة الإلكترونية من Firebase (FCM)][5] لجعل تطبيقك نشطًا مرة أخرى، ثم إرسال التحديثات إلى المربّع.

  • إذا كانت عملية مزامنة بيانات المربّعات مكلفة، يمكنك تنفيذ ما يلي:

    1. جدولة مزامنة البيانات.
    2. اضغَط على موقّت لمدة ثانية أو ثانيتَين.
    3. إذا تلقّيت تحديثًا من مصدر بيانات بعيد قبل نفاد الوقت، يمكنك عرض القيمة المعدّلة من مزامنة البيانات. بخلاف ذلك، اعرض قيمة محلية مخزنة مؤقتًا.