12

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

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

在我的应用程序的 Wear 部分,我想显示此列表的有限版本,例如列表中的前 3 个将显示在可穿戴设备上的全屏应用程序上。

我的问题是似乎没有办法将 Parcelable 对象发送到 Android Wear,在 DataItem 中没有放置 Parcelable 的选项。

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

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,这是正确的还是有更好的方法呢?

4

1 回答 1

18

捆绑式解决方案:

在我的应用程序中,我创建了一个轻量级类,专门用于将其从手机发送到观看。由于代码在应用程序的移动和可穿戴部分之间共享,因此可以在两个设备上轻松打包和恢复,无需重复代码。它提供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接口)。我没有在跨设备发送时对其进行测试,但它成功地发送到Parcelmarshall()unmarshall()从 Parcel 发送字节数组并将其存储在DataMap.

注意:我不确切知道 Google Play 服务是如何保存所有这些DataApi数据的,但我担心在更新此类时可能会出现问题。
例如,该类将在 Android Wear 上更新,用户将启动应用程序,该应用程序将尝试从中读取当前数据DataApi(使用此类的旧版本“序列化”)并尝试从中读取它,byte[]就好像它是更新版本一样. 应该对这些问题进行测试,但我不认为它们DataApi“仅仅因为”或者让在 Wear 上开发应用程序变得更加困难。

我强烈建议使用Bundle-like 解决方案并且不要使用该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上找到。

于 2014-09-20T12:02:45.757 回答