Двусторонняя связь Android между портативными и носимыми устройствами

Моя цель
Я создаю приложение/пакет, в котором носимое устройство и портативное устройство могут вносить изменения на уровне данных и получать уведомления о таких изменениях. Я использую GoogleApiClient и интерфейс DataApi.DataListener.

Текущий прогресс
На данный момент действие на моем носимом устройстве успешно обновляет счетчики на уровне данных, и это изменение затем обнаруживается и отражается на КПК посредством отображения новых счетчиков.

Проблема
Обнаружение работает только в одном направлении. В то время как изменение, инициированное носимым устройством, успешно обновляется на портативном устройстве, изменение, инициированное портативным устройством, не обнаруживается на носимом устройстве.

Что я пробовал
Я часами просматривал StackExchange и Google и не нашел случаев, когда и носимое устройство, и портативное устройство обновляли объекты уровня данных. В большинстве случаев КПК что-то обновлял, а носимое обнаруживало, или наоборот. Односторонняя связь меня устраивает. Мне нужен двусторонний.

Фрагмент кода для портативного компьютера

public class ListenActivity extends Activity implements
    DataApi.DataListener,
    GoogleApiClient.ConnectionCallbacks,
    GoogleApiClient.OnConnectionFailedListener {
// ConnectionCallback methods, UI methods not included in snippet

private static final String COUNT_KEY = "com.example.count";
private int count = 0;

@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_listen);

    handler.post(displayCounts);

    mGoogleApiClient = new GoogleApiClient.Builder(this)
            .addApi(Wearable.API)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build();
}

@Override
public void onDataChanged(DataEventBuffer dataEvents)
{
    for (DataEvent event : dataEvents)
    {
        if (event.getType() == DataEvent.TYPE_CHANGED)
        {
            DataItem item = event.getDataItem();
            if (item.getUri().getPath().compareTo("/count") == 0)
            {
                DataMap dataMap = DataMapItem.fromDataItem(item).getDataMap();
                count = dataMap.getInt(COUNT_KEY);
            }
        }
    }
}

// A UI button calls this method to reset the count, but the Wearable isn't calling its onDataChanged() method.
public void resetCount(View view)
{
    PutDataMapRequest putDataMapReq = PutDataMapRequest.create("/count");
    putDataMapReq.getDataMap().putInt(COUNT_KEY, 0);
    PutDataRequest putDataReq = putDataMapReq.asPutDataRequest();
    PendingResult<DataApi.DataItemResult> pendingResult =
            Wearable.DataApi.putDataItem(mGoogleApiClient, putDataReq);
} }

Фрагмент кода носимых устройств

public class WearListenActivity extends Activity implements
    DataApi.DataListener,
    GoogleApiClient.ConnectionCallbacks,
    GoogleApiClient.OnConnectionFailedListener {

// ConnectionCallback methods, UI methods not included in snippet

private static final String COUNT_KEY = "com.example.count";
private int count = 0;

@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mDismissOverlay = (DismissOverlayView) findViewById(R.id.dismiss_overlay);
    mDismissOverlay.showIntroIfNecessary();
    mGestureDetector = new GestureDetectorCompat(this, new GestureListener());

    mGoogleApiClient = new GoogleApiClient.Builder(this)
            .addApiIfAvailable(Wearable.API)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build();
}

// This method is never called on the Wearable. 
// It isn't detecting the changes made by Handheld's resetCount() method?
@Override
public void onDataChanged(DataEventBuffer dataEvents)
{
    for (DataEvent event : dataEvents)
    {
        if (event.getType() == DataEvent.TYPE_CHANGED)
        {
            DataItem item = event.getDataItem();
            if (item.getUri().getPath().compareTo("/count") == 0)
            {
                DataMap dataMap = DataMapItem.fromDataItem(item).getDataMap();
                count = dataMap.getInt(COUNT_KEY);
            }
        }
    }
}

// User taps the screen, this method is called. Works perfectly fine since handheld updates its counts.
private void updateDataLayer()
{
    PutDataMapRequest putDataMapReq = PutDataMapRequest.create("/count");
    putDataMapReq.getDataMap().putInt(COUNT_KEY, count);
    PutDataRequest putDataReq = putDataMapReq.asPutDataRequest();
    PendingResult<DataApi.DataItemResult> pendingResult =
            Wearable.DataApi.putDataItem(mGoogleApiClient, putDataReq);
} }

person meta.orphic    schedule 24.06.2015    source источник
comment
Есть ли в вашем носимом устройстве больше кода, где вы вызываете DataApi.addListener (например, в методе onConnected())? Любая конкретная причина, по которой вы регистрируете слушателя в каждом действии, а не в WearableListenerService, который будет работать независимо от того, запущена ваша активность или нет?   -  person ianhanniballake    schedule 24.06.2015
comment
У меня есть приложение, которое это делает. Код одинаков с обеих сторон, у меня есть общий класс диспетчера данных, который используют оба действия. Пара вещей, о которых следует помнить; ваша активность будет уведомлена, даже если это была та, которая внесла изменение, уведомления отправляются только в том случае, если данные отличаются от тех, что были раньше (двойная отправка одной и той же строки будет игнорироваться), а иногда в карте данных есть устаревшие данные. Для каждого элемента данных я сохраняю идентификатор устройства и отметку времени, чтобы учесть это. Опубликуйте больше кода вашего кода, и мы сможем найти проблему.   -  person blackcj    schedule 25.06.2015
comment
@ianhanniballake Да, я добавляю прослушиватель в метод onConnected(). Причина, по которой я регистрирую свой слушатель в каждом действии, заключается в том, что я реализую один модуль более крупного приложения, а остальной части приложения не требуются возможности прослушивания данных. Тем не менее, я все равно подумываю об использовании WearableListenerService, основываясь на всех ваших ответах/комментариях.   -  person meta.orphic    schedule 25.06.2015
comment
@blackcj Спасибо за предупреждение. Я понял все эти вещи, пройдя код несколько раз. Я собираюсь продолжить предложение каждого, включая ваше, и использовать отдельный/общий класс диспетчера данных.   -  person meta.orphic    schedule 25.06.2015


Ответы (1)


Это может быть связано с тем, что вы прослушиваете события в Activity. Я использую WearableListenerService, и он работает для в обоих направлениях.

Пример можно найти здесь: Обработка событий уровня данных

person Nick Moskalenko    schedule 25.06.2015
comment
Для вашего класса, расширяющего WearableListenerService, вы немедленно подключаетесь к GoogleApiClient в onCreate() или подключаетесь только для отправки данных, как в примере, который вы связали? - person meta.orphic; 26.06.2015
comment
Я поэкспериментировал с расширением WearableListenerService, и мне удалось заставить все работать. Большое спасибо! - person meta.orphic; 01.07.2015