مدیریت رویدادهای «لایه داده» در Wear

وقتی با «میانای برنامه‌سازی کاربردی لایه داده» تماس می‌گیرید، می‌توانید وضعیت تماس را پس‌از تکمیل شدن دریافت کنید. همچنین می‌توانید به رویدادهای داده‌ای ناشی از تغییرات داده‌ای که برنامه‌تان در هر جایی از شبکه Wear OS by Google ایجاد می‌کند گوش دهید.

برای نمونه‌ای از کار کردن مؤثر با Data Layer API، برنامه Android DataLayer Sample را ببینید.

منتظر وضعیت تماس‌های «لایه داده» بمانید

فراخوانی‌های «میانای برنامه‌سازی کاربردی لایه داده»—مثل فراخوانی بااستفاده از روش putDataItem کلاس DataClient—گاهی اوقات شیء Task<ResultType> را برمی‌گرداند. به‌محض اینکه شیء Task ایجاد شد، عملیات در پس‌زمینه در صف قرار می‌گیرد. اگر پس‌از این کار دیگری انجام ندهید، عملیات درنهایت بی‌صدا تکمیل می‌شود.

بااین‌حال، معمولاً می‌خواهید پس‌از تکمیل عملیات، کاری با نتیجه انجام دهید، بنابراین شیء Task به شما امکان می‌دهد وضعیت نتیجه را به‌صورت ناهمزمان یا همزمان انتظار بکشید.

تماس‌های غیرهمگام

اگر کدتان در رشته اصلی واسط کاربر اجرا می‌شود، برای میانای برنامه‌سازی کاربردی «لایه داده» فراخوانی‌های مسدودکننده انجام ندهید و از یک روتین همکار برای فراخوانی putDataItem استفاده کنید:

private suspend fun Context.sendDataAsync(count: Int) {
    try {
        val putDataReq: PutDataRequest = PutDataMapRequest.create("/count").run {
            dataMap.putInt("count_key", count)
            asPutDataRequest()
        }
        val dataItem = Wearable.getDataClient(this).putDataItem(putDataReq).await()
        handleDataItem(dataItem)
    } catch (e: Exception) {
        handleDataItemError(e)
    } finally {
        handleTaskComplete()
    }
}

private fun handleDataItem(dataItem: DataItem) { }
private fun handleDataItemError(exception: Exception) { }
private fun handleTaskComplete() { }

برای امکانات دیگر، ازجمله زنجیر کردن اجرای تکالیف مختلف، میانای برنامه‌سازی کاربردی تکلیف را ببینید.

تماس‌های هم‌زمان

اگر کدتان در رشته کنترل‌کننده جداگانه‌ای در سرویس پس‌زمینه‌ای اجرا می‌شود، مثلاً در WearableListenerService، از runBlocking برای ایجاد تماس مسدودکننده با putDataItem استفاده کنید.

توجه: این را درحالی‌که در رشته اصلی هستید فراخوانی نکنید.

private fun Context.sendDataSync(count: Int) = runBlocking {
    val putDataReq = PutDataMapRequest.create("/count").run {
        dataMap.putInt("count_key", count)
        asPutDataRequest()
    }

    try {
        val result = Wearable.getDataClient(this@sendDataSync)
            .putDataItem(putDataReq)
            .await()
        // Logic for success
    } catch (e: Exception) {
        // Handle failure
    }
}

گوش دادن به رویدادهای «لایه داده»

ازآنجایی‌که لایه داده‌ها داده‌ها را در دستگاه‌های دستی و پوشیدنی همگام‌سازی و ارسال می‌کند، معمولاً باید به رویدادهای مهمی مثل ایجاد شدن عناصر داده و دریافت پیام‌ها گوش دهید.

برای گوش دادن به رویدادهای لایه داده، دو گزینه دارید:

با هر دو این گزینه‌ها، روش‌های پاسخ‌گویی رویداد داده را برای رویدادهایی که می‌خواهید مدیریت کنید ملغی می‌کنید.

توجه: هنگام انتخاب پیاده‌سازی شنونده، مصرف باتری برنامه را درنظر بگیرید. WearableListenerService در مانیفست برنامه ثبت شده است و اگر برنامه ازقبل درحال اجرا نباشد می‌تواند آن را راه‌اندازی کند. اگر فقط زمانی نیاز دارید به رویدادها گوش دهید که برنامه‌تان درحال اجرا است، که اغلب در برنامه‌های تعاملی این‌گونه است، از WearableListenerService استفاده نکنید. به‌جای آن، شنونده زنده ثبت کنید. برای مثال، از روش addListener کلاس DataClient استفاده کنید. این کار می‌تواند بار سیستم و مصرف باتری را کاهش دهد.

استفاده از WearableListenerService

معمولاً نمونه‌هایی از WearableListenerService را در هر دو برنامه دست‌حمل و پوشیدنی‌تان ایجاد می‌کنید. بااین‌حال، اگر به رویدادهای داده در یکی از برنامه‌ها علاقه‌ای ندارید، نیازی نیست سرویس را در آن برنامه پیاده‌سازی کنید.

برای مثال، می‌توانید برنامه دستی داشته باشید که اشیای عنصر داده را تنظیم و دریافت می‌کند و برنامه پوشیدنی داشته باشید که این به‌روزرسانی‌ها را گوش می‌دهد تا واسط کاربر خود را به‌روز کند. برنامه دست‌بند هیچ‌یک از عناصر داده را به‌روزرسانی نمی‌کند، بنابراین برنامه تلفن همراه به هیچ‌یک از رویدادهای داده از برنامه دست‌بند گوش نمی‌دهد.

برخی‌از رویدادهایی که می‌توانید بااستفاده از WearableListenerService به آن‌ها گوش دهید عبارت‌اند از:

  • onDataChanged(): هرگاه یک شیء عنصر داده ایجاد، حذف، یا تغییر کند، سیستم این برگشت تماس را در همه گره‌های متصل راه‌اندازی می‌کند.
  • onMessageReceived(): پیامی که از یک گره ارسال می‌شود این بازخوان را در گره هدف راه‌اندازی می‌کند.
  • onCapabilityChanged(): وقتی قابلیت تبلیغ‌شده توسط نمونه برنامه شما در شبکه دردسترس قرار می‌گیرد، این رویداد باعث راه‌اندازی این بازخوان می‌شود. اگر به‌دنبال گرهی در نزدیکی خود هستید، می‌توانید روش isNearby() گره‌های ارائه‌شده در برگشت تماس را پُرسمان کنید.

همچنین می‌توانید رویدادهای ChannelClient.ChannelCallback، مانند onChannelOpened() را گوش کنید.

همه رویدادهای قبلی در یک رشته پس‌زمینه اجرا می‌شوند، نه در رشته اصلی.

برای ایجاد WearableListenerService، این مراحل را دنبال کنید:

  1. کلاسی ایجاد کنید که WearableListenerService را گسترش دهد.
  2. به رویدادهایی که به آن‌ها علاقه دارید، مثل onDataChanged()، گوش دهید.
  3. فیلتر هدفی را در مانیفست Android خود اعلام کنید تا سیستم را درباره WearableListenerService خود مطلع کنید. این بیانیه به سیستم اجازه می‌دهد سرویس شما را درصورت نیاز ملزم کند.

مثال زیر نحوه پیاده‌سازی WearableListenerService را نشان می‌دهد:

class DataLayerListenerService : WearableListenerService() {

    override fun onDataChanged(dataEvents: DataEventBuffer) {
        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "onDataChanged: $dataEvents")
        }

        // Loop through the events and send a message
        // to the node that created the data item.
        dataEvents
            .map { it.dataItem.uri }
            .forEach { uri ->
                // Get the node ID from the host value of the URI.
                val nodeId: String = uri.host!!
                // Set the data of the message to be the bytes of the URI.
                val payload: ByteArray = uri.toString().toByteArray()

                // Send the RPC.
                Wearable.getMessageClient(this)
                    .sendMessage(
                        nodeId,
                        DATA_ITEM_RECEIVED_PATH,
                        payload
                    )
            }
    }
}

بخش زیر توضیح می‌دهد که چگونه از فیلتر هدف با این شنونده استفاده کنید.

استفاده از فیلترها با WearableListenerService

فیلتر هدف برای مثال WearableListenerService نشان‌داده‌شده در بخش قبلی ممکن است به این شکل باشد:

<service
    android:name=".snippets.datalayer.DataLayerListenerService"
    android:exported="true"
    tools:ignore="ExportedService" >
    <intent-filter>
        <action android:name="com.google.android.gms.wearable.DATA_CHANGED" />
        <data
            android:scheme="wear"
            android:host="*"
            android:path="/start-activity" />
    </intent-filter>
</service>

فیلتر کنش DATA_CHANGED به سیستم می‌گوید که برنامه شما به رویدادهای لایه داده علاقه‌مند است.

در این مثال، ساعت به داده‌عنصر /start-activity گوش می‌دهد و تلفن به پاسخ پیام /data-item-received (DATA_ITEM_RECEIVED_PATH) گوش می‌دهد.

قوانین منطبق فیلتر استاندارد Android اعمال می‌شود. می‌توانید چندین سرویس در هر مانیفست، چندین فیلتر هدف در هر سرویس، چندین کنش در هر فیلتر، و چندین بخش داده در هر فیلتر مشخص کنید. فیلترها می‌توانند با میزبان عام یا میزبان خاصی مطابقت داشته باشند. برای مطابقت با میزبان نویسه عام، از host="*" استفاده کنید. برای مطابقت با میزبان خاص، host=<node_id> را مشخص کنید.

همچنین می‌توانید مسیر واقعی یا پیشوند مسیر را مطابقت دهید. برای انجام این کار، باید حرف عام یا میزبان خاصی را مشخص کنید. درغیراین‌صورت، سیستم مسیری را که مشخص کرده‌اید نادیده می‌گیرد.

برای کسب اطلاعات بیشتر درباره انواع فیلترهایی که Wear OS پشتیبانی می‌کند، به مستندات مرجع API برای WearableListenerService مراجعه کنید.

برای اطلاعات بیشتر درباره فیلترهای داده و قوانین مطابقت، به اسناد مرجع API برای عنصر مانیفست <data> مراجعه کنید.

هنگام مطابقت دادن فیلترهای هدف، دو قانون مهم را به‌یاد داشته باشید:

  • اگر طرحی برای فیلتر هدف مشخص نشده باشد، سیستم همه مشخصه‌های دیگر نشانی وب را نادیده می‌گیرد.
  • اگر میزبان برای فیلتر مشخص نشده باشد، سیستم همه مشخصه‌های مسیر را نادیده می‌گیرد.

استفاده از شنونده زنده

اگر برنامه شما فقط زمانی به رویدادهای لایه داده اهمیت می‌دهد که کاربر با برنامه تعامل دارد، ممکن است برای مدیریت هر تغییر داده‌ای به سرویس طولانی‌مدت نیاز نداشته باشد. در چنین مواردی، می‌توانید به رویدادهای فعالیت گوش دهید.

برای رویکردی پاک‌تر و ایمن‌تر، از ناظر چرخه حیات استفاده کنید. بااستفاده از ناظر چرخه حیات، منطق ثبت را از فعالیت LifecycleResumeEvent به کلاس جداگانه و قابل‌استفاده مجددی که DefaultLifecycleObserver را پیاده‌سازی می‌کند منتقل می‌کنید.

این رویکرد «فعالیت» شما را ساده نگه می‌دارد و از اشکالات رایج مثل فراموش کردن لغو ثبت شنونده جلوگیری می‌کند.

۱. ایجاد شنونده آگاه از چرخه حیات

این کلاس DataClient.OnDataChangedListener را می‌پیچد و به‌طور خودکار اشتراک خود را براساس چرخه حیات «فعالیت» مدیریت می‌کند.

class WearDataLayerObserver(
    private val dataClient: DataClient,
    private val onDataReceived: (DataEventBuffer) -> Unit
) : DefaultLifecycleObserver, DataClient.OnDataChangedListener {

    // Implementation of the DataClient listener
    override fun onDataChanged(dataEvents: DataEventBuffer) {
        onDataReceived(dataEvents)
    }

    // Automatically register when the Activity starts
    override fun onResume(owner: LifecycleOwner) {
        dataClient.addListener(this)
    }

    // Automatically unregister when the Activity pauses
    override fun onPause(owner: LifecycleOwner) {
        dataClient.removeListener(this)
    }
}

۲. استفاده در «فعالیت‌های شما»

اکنون، فعالیت شما برای Wear API نیازی به استفاده از LifecycleResumeEvent یا onPause ندارد. ناظر را یک‌بار در LaunchedEvent (یا onCreate) ثبت می‌کنید.

class DataLayerLifecycleActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val dataClient = Wearable.getDataClient(this)

        // Create the observer and link it to the activity's lifecycle
        val wearObserver = WearDataLayerObserver(dataClient) { dataEvents ->
            handleDataEvents(dataEvents)
        }

        lifecycle.addObserver(wearObserver)
    }

    private fun handleDataEvents(dataEvents: DataEventBuffer) {
        // ... filter and process events ...
    }
}

چرا این بهتر است:

  • فعالیت پاک‌کننده: کلیشه‌ها را از روش‌های چرخه حیات «فعالیت» برمی‌دارید.
  • ایمنی: DefaultLifecycleObserver کمک می‌کند تأیید شود که شنونده حتی اگر «فعالیت» به‌طور غیرمنتظره‌ای ازبین برود برداشته می‌شود، و از این طریق از نشت حافظه جلوگیری می‌کند.
  • قابلیت استفاده مجدد: می‌توانید این WearDataLayerObserver را بدون بازنویسی منطق ثبت در هر «فعالیت» یا «ترکیب‌شونده» وصل کنید.
  • جداسازی: منطق زمان گوش دادن از منطق کاری که باید با داده‌ها انجام شود جدا می‌شود.

استفاده از فیلترها با شنوندگان زنده

همان‌طور که قبلاً ذکر شد، همان‌گونه که می‌توانید فیلترهای هدف را برای اشیاء مبتنی بر مانیفست WearableListenerService مشخص کنید، می‌توانید هنگام ثبت شنونده زنده ازطریق Wearable API از فیلترهای هدف استفاده کنید. قوانین یکسانی برای هر دو شنونده زنده مبتنی بر API و شنونده مبتنی بر مانیفست اعمال می‌شود.

الگوی رایج این است که شنونده‌ای را با مسیر یا پیشوند مسیر خاصی ثبت کنید بااستفاده از collectAsStateWithLifecycle(). با پیاده‌سازی شنوندگان به این روش، برنامه شما می‌تواند رویدادها را به‌صورت انتخابی‌تر دریافت کند و طراحی و کارایی آن را بهبود بخشد.