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


我刚学习如何开发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,这是正确的还是有更好的方法呢?


12082
2017-09-19 16:17


起源

你最终使用Bundle或Parcelable解决方案了吗?有什么建议? - riper


答案:


捆绑式解决方案:

在我的应用程序中,我创建了一个轻量级的类,专门用于从手机发送到手表。由于代码在应用程序的移动和可穿戴部分之间共享,因此可以在两个设备上轻松打包和恢复,而无需重复代码。它提供 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 (使用此类的旧版本“序列化”)并尝试从中读取它 byte[] 好像它是更新版本。应该测试这些问题,但我不认为他们做了 DataApi 如此原始的“只是因为”或者更难以在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上


15
2017-09-20 12:02



我不认为您对解组Parcelable数据的担忧是正确的;移动应用程序更新后,可穿戴应用程序也会更新。在野外,不太可能一起使用不同的版本,我能想象的唯一场景是在安装更新的磨损APK的短时间内。 - Paul Lammertsma
一个相当优雅的解决方案是将编组的模型放置在移动和可穿戴模块之间的共享模块中。 - Paul Lammertsma
@Maciej - 你对使用Parcelable还有同样的看法吗? - riper
@PaulLammertsma“当移动应用程序更新时,可穿戴应用程序也会更新” - 即使只在移动应用程序上增加了versionCode? - EyesClear
我相信,当移动应用程序完全不管版本代码时,磨损应用程序总是会更新。你会在开发时体验到这一点;在每次运行中,磨损应用程序被发送到可穿戴设备。 - Paul Lammertsma