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

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

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

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

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

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

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

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