我可以将自定义对象发送到Android Wear吗?

时间:2014-09-19 16:17:01

标签: android parcelable serializable wear-os android-wear-data-api

我正在学习如何开发Android Wear,我已经为智能手表创建了一个全屏活动,在我的应用程序的移动部分,我获得了一些JSON数据,并从中创建了一个自定义对象列表。

在我的移动应用程序中,我在ListView中显示这些对象的信息。

在我的应用程序的Wear部分,我想显示此列表的限制版本,例如列表中的前3个将显示在Wearable上的全屏应用程序中。

我的问题是似乎没有办法将Parcelable Objects发送到Android Wear,因此没有选项将putParcelable放在DataItem中。

看起来唯一的选择是以字节为单位发送对象,如下所示:

public void sendWearableData(GoogleApiClient aGoogleApiClient, ArrayList<MyObject> myObjectList, String path)
{

    googleApiClient = aGoogleApiClient;

    byte[] testBytes = new byte[0];

    if (googleApiClient.isConnected()) {
        PutDataMapRequest dataMapRequest = PutDataMapRequest.create(path);
        try {
            testBytes = BytesUtils.toByteArray(myObjectList);
        } catch (IOException e) {
            e.printStackTrace();
        }
        dataMapRequest.getDataMap().putByteArray(Constants.TEST_KEY, testBytes);
        PutDataRequest request = dataMapRequest.asPutDataRequest();
        Wearable.DataApi.putDataItem(googleApiClient, request);
    }
}

所以我必须将我的对象转换为字节,将其发送到Android Wear并将其转换回来?这意味着我已经实现了Parcelable的对象,所以我现在可以通过Intents发送它们也需要实现Serializable,这是正确的还是有更好的方法呢?

1 个答案:

答案 0 :(得分:16)

类似Bundle的解决方案:

在我的应用程序中,我创建了一个轻量级的课程,专门用于从手机发送到手表。由于代码在应用程序的移动和可穿戴部分之间共享,因此可以在两个设备上轻松打包和恢复,而无需重复代码。它提供Bundle - 类似机制,但使用DataMap

示例实施:

public class MyObject {

    public final long itemId;
    public final long sortOrder;
    public final String priceString;

    public MyObject(long itemId, long sortOrder, String priceString) {
        this.itemId = itemId;
        this.sortOrder = sortOrder;
        this.priceString = priceString;
    }

    public MyObject(DataMap map) {
        this(map.getLong("itemId"),
             map.getLong("sortOrder"),
             map.getString("priceString")
            );
    }

    public DataMap putToDataMap(DataMap map) {
        map.putLong("itemId", itemId);
        map.putLong("sortOrder", sortOrder);
        map.putString("priceString", priceString);
        return map;
    }
}

编写这样的类将让您考虑实际需要在设备之间发送的内容尽可能少地发送。当添加或删除任何字段时,它也不会中断(与下一个解决方案相反)。

回答您的Parcelable问题:

如果您不想编写新课程并希望重复使用现有代码,可以尝试使用以下代码。它将让您只使用Parcelable接口(无需实现Serializable接口)。我在发送设备时没有对其进行测试,但是成功将marshall()unmarshall()字节数组发送到Parcel,并将其存储在DataMap中。

注意:我并不确切知道Google Play服务如何保存所有这些DataApi数据,但我担心当这样的课程会出现问题时可能会出现问题更新。
例如,该类将在Android Wear上更新,用户将启动尝试从DataApi读取当前数据的应用程序(即#34;序列化&#34;使用此类的旧版本)并尝试从byte[]读取它,好像它是更新版本一样。应该测试这些问题,但我不认为他们DataApi如此原始&#34;只是因为&#34;或者更加努力地开发Wear上的应用程序。

我强烈建议您使用Bundle - 类似解决方案,不要使用Parcelable解决方案 使用此风险需要您自担风险。

import android.os.Parcel;
import android.os.Parcelable;

import com.google.android.gms.wearable.DataMap;

/**
 * <p>Allows to put and get {@link Parcelable} objects into {@link DataMap}</p>
 * <b>USAGE:</b>
 * <p>
 * <b>Store object in DataMap:</b><br/>
 * DataMapParcelableUtils.putParcelable(dataMap, "KEY", myParcelableObject);
 * </p><p>
 * <b>Restore object from DataMap:</b><br/>
 * myParcelableObject = DataMapParcelableUtils.getParcelable(dataMap, "KEY", MyParcelableObject.CREATOR);
 * </p>
 * I do <b>not recommend</b> to use this method - it may fail when the class that implements {@link Parcelable} would be updated. Use it at your own risk.
 * @author Maciej Ciemięga
 */
public class DataMapParcelableUtils {

    public static void putParcelable(DataMap dataMap, String key, Parcelable parcelable) {
        final Parcel parcel = Parcel.obtain();
        parcelable.writeToParcel(parcel, 0);
        parcel.setDataPosition(0);
        dataMap.putByteArray(key, parcel.marshall());
        parcel.recycle();
    }

    public static <T> T getParcelable(DataMap dataMap, String key, Parcelable.Creator<T> creator) {
        final byte[] byteArray = dataMap.getByteArray(key);
        final Parcel parcel = Parcel.obtain();
        parcel.unmarshall(byteArray, 0, byteArray.length);
        parcel.setDataPosition(0);
        final T object = creator.createFromParcel(parcel);
        parcel.recycle();
        return object;
    }
}

该代码也可在GitHub上找到。