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

Posted

技术标签:

【中文标题】我可以将自定义对象发送到 Android Wear 吗?【英文标题】:Can I send custom objects to Android Wear? 【发布时间】:2014-11-14 07:20:00 【问题描述】:

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

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

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

我的问题是似乎没有办法将 Parcelable 对象发送到 Android Wear,没有将 Parcelable 放入 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,这是正确的还是有更好的方法?

【问题讨论】:

您最终使用的是 Bundle 还是 Parcelable 解决方案?有什么建议吗? 【参考方案1】:

类似捆绑的解决方案:

在我的应用程序中,我创建了一个轻量级类,专门用于将其从手机发送到观看。由于代码在应用程序的移动和可穿戴部分之间共享,因此可以在两个设备上轻松打包和恢复,而无需重复代码。它提供Bundle-like 机制,但使用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-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 上找到。

【讨论】:

我不认为您对解组 Parcelable 数据的担忧是公正的;当移动应用程序更新时,可穿戴应用程序也会更新。在野外,不同版本一起使用的可能性很小,我能想象的唯一场景是安装更新后的 Wear APK 的短时间内。 一个相当优雅的解决方案是将编组的模型放入移动和可穿戴模块之间的共享模块中。 @Maciej - 您对使用 Parcelable 的看法是否仍然相同? @PaulLammertsma “当移动应用更新时,可穿戴应用也会更新” - 即使仅在移动应用上增加 versionCode?​​span> 我相信穿戴应用总是在移动应用更新的时候更新,完全不管versionCodes。你会在开发时体验到这一点;每次运行时,都会将穿戴应用程序发送到可穿戴设备。

以上是关于我可以将自定义对象发送到 Android Wear 吗?的主要内容,如果未能解决你的问题,请参考以下文章

将自定义对象存储到 Android 内部存储的最佳方式?

如何向 Android Wear TileService 发送数据

如何在睡眠模式下唤醒 Android Wear?

Android将自定义对象从服务传递给活动

Android Wear OS 在后台检索计步器

使用 pymongo 将自定义 python 对象编码为 BSON