Wear'da Veri Katmanı etkinliklerini işleme

Veri katmanı API'sine çağrı yaptığınızda, çağrı tamamlandığında çağrının durumunu alabilirsiniz. Ayrıca, uygulamanızın Wear OS by Google ağında yaptığı veri değişikliklerinden kaynaklanan veri etkinliklerini de dinleyebilirsiniz.

Veri Katmanı API'si ile etkili bir şekilde çalışmaya dair örnek için Android DataLayer Sample uygulamasına göz atın.

Veri katmanı çağrılarının durumunu bekleyin.

Data Layer API'ye yapılan çağrılar (ör. putDataItem sınıfının DataClient yöntemi kullanılarak yapılan bir çağrı) bazen Task<ResultType> nesnesi döndürür. Task nesnesi oluşturulur oluşturulmaz işlem arka planda sıraya alınır. Bundan sonra başka bir işlem yapmazsanız işlem sonunda sessizce tamamlanır.

Ancak, işlem tamamlandıktan sonra genellikle sonuçla ilgili bir işlem yapmak istersiniz. Bu nedenle, Task nesnesi, sonucu eşzamansız veya eşzamanlı olarak beklemenize olanak tanır.

Asenkron aramalar

Kodunuz ana kullanıcı arayüzü iş parçacığında çalışıyorsa Veri Katmanı API'sine engelleyici çağrılar yapmayın. İşlem tamamlandığında tetiklenen bir geri çağırma yöntemi ekleyerek çağrıları eşzamansız olarak çalıştırın: Task nesnesine geri çağırma yöntemi ekleyin:

Kotlin

// Using Kotlin function references
task.addOnSuccessListener(::handleDataItem)
task.addOnFailureListener(::handleDataItemError)
task.addOnCompleteListener(::handleTaskComplete)
...
fun handleDataItem(dataItem: DataItem) { ... }
fun handleDataItemError(exception: Exception) { ... }
fun handleTaskComplete(task: Task<DataItem>) { ... }

Java

// Using Java 8 Lambdas.
task.addOnSuccessListener(dataItem -> handleDataItem(dataItem));
task.addOnFailureListener(exception -> handleDataItemError(exception));
task.addOnCompleteListener(task -> handleTaskComplete(task));

Farklı görevlerin yürütülmesini zincirleme gibi diğer olasılıklar için Task API'ye bakın.

Eşzamanlı aramalar

Kodunuz arka plan hizmetinde ayrı bir işleyici iş parçacığında (ör. WearableListenerService) çalışıyorsa çağrıların engellenmesi sorun olmaz. Bu durumda, Task nesnesinde Tasks.await() işlevini çağırabilirsiniz. Bu işlev, istek tamamlanana kadar engeller ve Result nesnesi döndürür. Bu durum aşağıdaki örnekte gösterilmektedir.

Not: Ana iş parçacığındayken bu işlevi çağırmadığınızdan emin olun.

Kotlin

try {
    Tasks.await(dataItemTask).apply {
        Log.d(TAG, "Data item set: $uri")
    }
}
catch (e: ExecutionException) { ... }
catch (e: InterruptedException) { ... }

Java

try {
    DataItem item = Tasks.await(dataItemTask);
    Log.d(TAG, "Data item set: " + item.getUri());
} catch (ExecutionException | InterruptedException e) {
  ...
}

Veri katmanı etkinliklerini dinleme

Veri katmanı, verileri senkronize edip elde taşınır ve giyilebilir cihazlara gönderdiğinden genellikle veri öğelerinin oluşturulması ve mesajların alınması gibi önemli etkinlikleri dinlemeniz gerekir.

Veri katmanı etkinliklerini işlemek için iki seçeneğiniz vardır:

Bu seçeneklerin her ikisinde de, ilgilendiğiniz etkinlikler için veri etkinliği geri çağırma yöntemlerini geçersiz kılarsınız.

Not: Bir dinleyici uygulaması seçerken uygulamanızın pil kullanımını göz önünde bulundurun. Uygulamanın manifestinde bir WearableListenerService kayıtlıdır ve uygulama henüz çalışmıyorsa uygulamayı başlatabilir. Yalnızca uygulamanız zaten çalışırken etkinlikleri dinlemeniz gerekiyorsa (bu durum genellikle etkileşimli uygulamalarda geçerlidir) WearableListenerService kullanmayın. Bunun yerine canlı bir işleyici kaydedin. Örneğin, DataClient sınıfının addListener yöntemini kullanın. Bu işlem, sistemdeki yükü ve pil kullanımını azaltabilir.

WearableListenerService kullanma

Genellikle hem giyilebilir cihaz hem de elde taşınabilir cihaz uygulamalarınızda WearableListenerService örnekleri oluşturursunuz. Ancak uygulamalardan birindeki veri etkinlikleriyle ilgilenmiyorsanız hizmeti bu uygulamada uygulamanız gerekmez.

Örneğin, veri öğesi nesnelerini ayarlayan ve alan bir elde taşınabilir uygulama ile kullanıcı arayüzünü güncellemek için bu güncellemeleri dinleyen bir giyilebilir cihaz uygulaması olabilir. Giyilebilir cihaz uygulaması hiçbir veri öğesini güncellemediğinden elde taşınır cihaz uygulaması, giyilebilir cihaz uygulamasından gelen veri etkinliklerini dinlemez.

WearableListenerService kullanarak dinleyebileceğiniz etkinliklerden bazıları şunlardır:

  • onDataChanged(): Bir veri öğesi nesnesi oluşturulduğunda, silindiğinde veya değiştirildiğinde sistem, bağlı tüm düğümlerde bu geri çağırmayı tetikler.
  • onMessageReceived(): Bir düğümden gönderilen mesaj, hedef düğümde bu geri çağırmayı tetikler.
  • onCapabilityChanged(): Uygulamanızın bir örneğinin reklamını yaptığı bir özellik ağda kullanıma sunulduğunda bu etkinlik geri çağırmayı tetikler. Yakınlardaki bir düğümü arıyorsanız geri çağırmada sağlanan düğümlerin isNearby() yöntemini sorgulayabilirsiniz.

Ayrıca ChannelClient.ChannelCallback'daki onChannelOpened() gibi etkinlikleri de dinleyebilirsiniz.

Önceki tüm etkinlikler ana iş parçacığında değil, arka plan iş parçacığında yürütülür.

WearableListenerService oluşturmak için şu adımları uygulayın:

  1. WearableListenerService sınıfını genişleten bir sınıf oluşturun.
  2. İlgilendiğiniz etkinlikleri dinleyin (ör. onDataChanged()).
  3. Sistemi WearableListenerService hakkında bilgilendirmek için Android manifestinizde bir intent filtresi tanımlayın. Bu bildirim, sistemin hizmetinizi gerektiği gibi bağlamasına olanak tanır.

Aşağıdaki örnekte, basit bir WearableListenerService öğesinin nasıl uygulanacağı gösterilmektedir:

Kotlin

private const val TAG = "DataLayerSample"
private const val START_ACTIVITY_PATH = "/start-activity"
private const val DATA_ITEM_RECEIVED_PATH = "/data-item-received"

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

Java

public class DataLayerListenerService extends WearableListenerService {
    private static final String TAG = "DataLayerSample";
    private static final String START_ACTIVITY_PATH = "/start-activity";
    private static final String DATA_ITEM_RECEIVED_PATH = "/data-item-received";

    @Override
    public void onDataChanged(DataEventBuffer dataEvents) {
        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.
        for (DataEvent event : dataEvents) {
            Uri uri = event.getDataItem().getUri();

            // Get the node ID from the host value of the URI.
            String nodeId = uri.getHost();
            // Set the data of the message to be the bytes of the URI.
            byte[] payload = uri.toString().getBytes();

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

Aşağıdaki bölümde, bu işleyiciyle amaç filtresinin nasıl kullanılacağı açıklanmaktadır.

WearableListenerService ile filtreleri kullanma

Önceki bölümde gösterilen WearableListenerService örneği için bir amaç filtresi şöyle görünebilir:

<service android:name=".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>

Bu filtrede, yalnızca belirli etkinliklerin uygulamanızı uyandırması veya başlatması için DATA_CHANGED işlemi, daha önce önerilen BIND_LISTENER işleminin yerini alır. Bu değişiklik, sistem verimliliğini artırır ve pil tüketimini azaltır. Ayrıca, uygulamanızla ilişkili diğer ek yükleri de azaltır. Bu örnekte, kol saati /start-activity veri öğesini, telefon ise /data-item-received mesaj yanıtını dinler.

Standart Android filtre eşleştirme kuralları geçerlidir. Manifest başına birden fazla hizmet, hizmet başına birden fazla amaç filtresi, filtre başına birden fazla işlem ve filtre başına birden fazla veri stanza'sı belirtebilirsiniz. Filtreler, joker karakterli bir ana makineyle veya belirli bir ana makineyle eşleşebilir. Joker karakter ana makineyle eşleşmek için host="*" kullanın. Belirli bir ana makineyle eşleşmek için host=<node_id> değerini belirtin.

Ayrıca, tam bir yolu veya yol ön ekini de eşleştirebilirsiniz. Bunu yapmak için joker karakter veya belirli bir ana makine belirtmeniz gerekir. Aksi takdirde sistem, belirttiğiniz yolu yoksayar.

Wear OS'in desteklediği filtre türleri hakkında daha fazla bilgi için WearableListenerService API referans dokümanlarına bakın.

Veri filtreleri ve eşleştirme kuralları hakkında daha fazla bilgi için <data> manifest öğesiyle ilgili API referans belgelerine bakın.

Amaç filtrelerini eşleştirirken iki önemli kuralı unutmayın:

  • Niyet filtresi için şema belirtilmemişse sistem diğer tüm URI özelliklerini yoksayar.
  • Filtre için ana makine belirtilmemişse sistem tüm yol özelliklerini yok sayar.

Canlı dinleyici kullanma

Uygulamanız yalnızca kullanıcı uygulamayla etkileşimde bulunurken veri katmanı etkinlikleriyle ilgileniyorsa her veri değişikliğini işlemek için uzun süreli bir hizmete ihtiyacı olmayabilir. Bu gibi durumlarda, aşağıdaki arayüzlerden birini veya daha fazlasını uygulayarak bir etkinlikteki etkinlikleri dinleyebilirsiniz:

Veri etkinliklerini dinleyen bir etkinlik oluşturmak için aşağıdakileri yapın:

  1. İstediğiniz arayüzleri uygulayın.
  2. onCreate() veya onResume() yönteminde, Google Play hizmetlerine etkinliğinizin veri katmanı etkinliklerini dinlemek istediğini bildirmek için Wearable.getDataClient(this).addListener(), MessageClient.addListener(), CapabilityClient.addListener() veya ChannelClient.registerChannelCallback() işlevini çağırın.
  3. onStop() veya onPause() içinde DataClient.removeListener(), MessageClient.removeListener(), CapabilityClient.removeListener() ya da ChannelClient.unregisterChannelCallback() ile tüm dinleyicilerin kaydını silin.
  4. Bir etkinlik yalnızca belirli bir yol önekine sahip olaylarla ilgileniyorsa yalnızca mevcut uygulama durumuyla alakalı verileri almak için uygun bir önek filtresiyle bir dinleyici ekleyebilirsiniz.
  5. Uyguladığınız arayüzlere bağlı olarak onDataChanged(), onMessageReceived(), onCapabilityChanged() veya ChannelClient.ChannelCallback yöntemlerini uygulayın. Bu yöntemler ana iş parçacığında çağrılır veya WearableOptions kullanarak özel bir Looper belirtebilirsiniz.

DataClient.OnDataChangedListener'nın uygulandığı bir örneği aşağıda görebilirsiniz:

Kotlin

class MainActivity : Activity(), DataClient.OnDataChangedListener {

    public override fun onResume() {
        Wearable.getDataClient(this).addListener(this)
    }

    override fun onPause() {
        Wearable.getDataClient(this).removeListener(this)
    }

    override fun onDataChanged(dataEvents: DataEventBuffer) {
        dataEvents.forEach { event ->
            if (event.type == DataEvent.TYPE_DELETED) {
                Log.d(TAG, "DataItem deleted: " + event.dataItem.uri)
            } else if (event.type == DataEvent.TYPE_CHANGED) {
                Log.d(TAG, "DataItem changed: " + event.dataItem.uri)
            }
        }
    }
}

Java

public class MainActivity extends Activity implements DataClient.OnDataChangedListener {

    @Override
    public void onResume() {
        Wearable.getDataClient(this).addListener(this);
    }

    @Override
    protected void onPause() {
        Wearable.getDataClient(this).removeListener(this);
    }

    @Override
    public void onDataChanged(DataEventBuffer dataEvents) {
        for (DataEvent event : dataEvents) {
            if (event.getType() == DataEvent.TYPE_DELETED) {
                Log.d(TAG, "DataItem deleted: " + event.getDataItem().getUri());
            } else if (event.getType() == DataEvent.TYPE_CHANGED) {
                Log.d(TAG, "DataItem changed: " + event.getDataItem().getUri());
            }
        }
    }
}

Dikkat: Wearable Data Layer API'yi kullanmadan önce API'nin cihazda kullanılabilir olduğunu kontrol edin. Aksi takdirde istisna oluşur. Horologist'te uygulandığı gibi GoogleApiAvailability sınıfını kullanın.

Canlı dinleyicilerle filtreleri kullanma

Daha önce de belirtildiği gibi, manifest tabanlı WearableListenerService nesneler için amaç filtreleri belirtebildiğiniz gibi Wearable API aracılığıyla canlı dinleyici kaydederken de amaç filtrelerini kullanabilirsiniz. Aynı kurallar hem API tabanlı canlı dinleyiciler hem de manifest tabanlı dinleyiciler için geçerlidir.

Yaygın bir yöntem, bir etkinliğin onResume() yönteminde belirli bir yolla veya yol önekiyle bir dinleyici kaydetmek, ardından etkinliğin onPause() yönteminde dinleyiciyi kaldırmaktır. Dinleyicileri bu şekilde uygulamak, uygulamanızın etkinlikleri daha seçici bir şekilde almasını sağlayarak tasarımını ve verimliliğini artırır.