【问题标题】:Mobile Backend Starter subscribeToCloudMessage will not work移动后端启动器 subscribeToCloudMessage 将不起作用
【发布时间】:2014-04-03 01:51:48
【问题描述】:

当我使用 CloudBackendMessaging.TOPIC_ID_BROADCAST 作为 topicId 的 subscribeToCloudMessage() 函数时,就像在 CloudBackendFragment.java 中所做的那样,一切正常,但是当我给这个函数我自己的字符串时,我收到了这条消息:

错误:

m.google.api.client.googleapis.json.GoogleJsonResponseException: 400 Bad Request

"code": 400,
"errors": [
  {
    "domain": "global",
    "message": "SubscriptionIDs: String properties must be 500 characters or less.  Instead, use com.google.appengine.api.datastore.Text, which can store strings of any length.",
    "reason": "badRequest"
  }
],
"message": "SubscriptionIDs: String properties must be 500 characters or less.  Instead, use com.google.appengine.api.datastore.Text, which can store strings of any length."

at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:111)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:38)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:312)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1042)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:410)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:343)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:460)
at com.google.cloud.backend.core.CloudBackend.list(CloudBackend.java:314)
at com.google.cloud.backend.core.CloudBackendAsync.access$8(CloudBackendAsync.java:1)
at com.google.cloud.backend.core.CloudBackendAsync$9.callBackend(CloudBackendAsync.java:270)
at com.google.cloud.backend.core.CloudBackendAsync$9.callBackend(CloudBackendAsync.java:1)
at com.google.cloud.backend.core.CloudBackendAsync$BackendCaller.run(CloudBackendAsync.java:402)

【问题讨论】:

    标签: java android json google-maps google-app-engine


    【解决方案1】:

    此错误消息表示属性 SubscriptionIDs(您可以在数据存储中的 _DeviceSubscription Kind 下找到它)值超过 500 个 Unicode 字符的限制。阅读docs 以供参考。

    来自文档:

    对于文本字符串和未编码的二进制数据(字节字符串), Datastore 支持两种值类型:

    1. 索引短字符串(最多 500 个 Unicode 字符或字节) 并可用于查询过滤条件和排序顺序。
    2. 长字符串(最大 1 兆字节)没有索引,不能用于查询过滤器和排序顺序。

    发生这种情况的原因是 MBS 试图将所有订阅写入一个属性。

    因此,为了解决这个问题,我们需要使用 Text 而不是 String 为 MBS backend source code 输入 SubscriptionIDs 属性。为此,您需要在 DeviceSubscription.java 类中进行以下更改:

    要设置Text属性替换这行代码:

    deviceSubscription.setProperty(PROPERTY_SUBSCRIPTION_IDS, this.gson.toJson(subscriptions));
    

    用这一行:

    deviceSubscription.setProperty(PROPERTY_SUBSCRIPTION_IDS, new Text(this.gson.toJson(subscriptions)));
    

    从数据存储中获取Text 属性:

    1. 替换这一行:

      String subscriptionString = (String) deviceSubscription.getProperty(PROPERTY_SUBSCRIPTION_IDS);
      

      用这个:

      Text text = (Text) deviceSubscription.getProperty(PROPERTY_SUBSCRIPTION_IDS);
          String subscriptionString = text.getValue();
      
    2. 替换这一行:

      String ids = (String) deviceSubscription.getProperty(PROPERTY_SUBSCRIPTION_IDS);
      

      用这个:

      Text text = (Text) deviceSubscription.getProperty(PROPERTY_SUBSCRIPTION_IDS);
            String ids = text.getValue();
      
    3. 替换这一行:

      String[] ids = new Gson().fromJson((String) entity.getProperty(PROPERTY_SUBSCRIPTION_IDS),
                  String[].class);
      

      用这个:

      Text text = (Text) entity.getProperty(PROPERTY_SUBSCRIPTION_IDS);
              String[] ids = new Gson().fromJson(text.getValue(), String[].class);
      

    似乎是有效的解决方案。到目前为止,我还没有注意到对我的项目有负面影响。

    注意:正如文档所述,Text未编入索引,不能用于查询过滤器和排序顺序。因此,如果需要对属性 SubscriptionIDs 进行索引,则此限制可能会导致另一个问题。

    【讨论】:

    • 你可能是指 DeviceSubstription.java 的服务器端代码?有人可以确认这是否有效吗?我认为问题可能出在其他地方(请参阅我的其他评论)。但如果不是,则应将其报告为错误。或者有工作版本的人应该发送拉取请求。
    • @r-hold 是的,您需要更改服务器端代码。这对我仍然有效。我想这是一个错误。
    【解决方案2】:

    我去了 cloud.google.com 查询视图并删除了我的旧 device_subscription ID,此后它运行良好。不确定你是否能够做到这一点。

    【讨论】:

      【解决方案3】:

      似乎订阅 id 是使用某种算法生成的,该算法主要使用您首次启动移动后端启动应用程序时获得的 regid。为了解决这个问题,我只是在给定的 regid 上调用了 substring 并大大缩短了它,但仍然保留了足够长的时间以保证某种程度的唯一性。

      私有静态字符串doRegister(上下文上下文){ 字符串味精 = ""; 尝试 { GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context); 字符串 regId = gcm.register(Consts.PROJECT_NUMBER).substring(0,16); msg = "设备已注册,注册ID=" + regId;

      此方法位于 GCMIntentService.java 文件中。 注意

      .substring(0,16);

      为我工作!只是想我会分享。

      【讨论】:

      • 谢谢,结合 Julien 的修复,这对我有用。您是否尝试过更长的子字符串?正如我所见,这不应该达到 499 吗?
      • 对于任何来这里寻找解决方案的人,请关注this 文章。
      【解决方案4】:

      根据文档,@Juniper 的回答是有意义的。 @jamrockRay 的回答对我不起作用。

      但是我有一种感觉,这可能与作为 Entitykind 传递的字符串的值有关。如果我将其从“留言簿”(如示例中)更改为其他内容,则会发生错误。如果我把它改回来,一切都会按预期工作,即使有不同的实体属性。你能确认一下吗?

      【讨论】:

      • 我看不到种类名称与此错误之间的任何关系。发生这种情况的原因是 MBS 试图将所有订阅写入一个属性。默认情况下,MBS 仅使用一个 GCM 订阅,该订阅始终少于 500 个字符的限制。当多个 SubscriptionID 尝试写入一个属性时会发生错误。我猜您不仅更改了种类名称“Guestbook”,而且还修改了一些添加额外订阅 ID 的代码。例如 Scope.FUTURE 和 Scope.FUTURE_AND_PAST 在您的查询中添加更多订阅。
      • 我明白你的意思,它也让我感到困惑。但我已经仔细检查过了。我正在使用 fork 中的示例以及为 Android Studio github.com/thagikura/… 准备的示例,它已经默认使用“Scope.FUTURE_AND_PAST”。是的,我已经在某些地方修改了代码,但是一旦我将我的 entitykind 名称改回“Guestbook”,它就会再次工作。只要我有时间进行自定义部署,就会尝试您的解决方案。
      • @Juniper 我终于找到时间来实施您建议的错误修复并解散它们。我可以确认:它对我有用。仍然困惑为什么更改 KIND_NAME 会搞砸。
      • @r-hold 我在使用相同的后端启动器时遇到了与您完全相同的问题。如果我使用留言簿,它可以工作,如果我使用其他任何东西,我会得到同样的错误。我知道在创建实体时我没有做任何奇怪的事情,因为我使用完全相同的方法只是更改 KindName。很奇怪
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-05
      • 2014-02-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多