java - Google Cloud Messaging - 即时收到或延迟很长时间的消息

标签 java android google-cloud-messaging

我在大学最后一年的项目中使用了 Google 云消息传递。一切正常,但我在使用 GCM 时遇到了一些麻烦。通常情况下,消息要么几乎是即时传递,要么有很长的延迟。

我读过这篇文章,但我真的认为它不适用于这种情况:

GCM will usually deliver messages immediately after they are sent. However, this might not always be possible. For example, the device could be turned off, offline, or otherwise unavailable. In other cases, the sender itself might request that messages not be delivered until the device becomes active by using the delay_while_idle flag. Finally, GCM might intentionally delay messages to prevent an application from consuming excessive resources and negatively impacting battery life.

在我的项目中,每分钟最多讨论来自服务器的 5 或 6 条消息。如果 GCM 可以用于聊天应用程序,他们肯定不能阻止以这种速率发送/接收的消息吗?如果我的项目只能在 50% 的时间内工作,它会变得非常烦人并且会非常糟糕......

这是服务器发送消息的代码:

@Override
public void run() {

    Message.Builder messageBuilder = new Message.Builder().delayWhileIdle(false);
    Gson gson = new Gson();
    messageBuilder.addData("profile", gson.toJson(profile));
    databaseConnection.notifyDevices(messageBuilder.build());

}

public void notifyDevices(Message message) {

        Sender sender = new Sender(xxx);

        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
        nameValuePairs.add(new BasicNameValuePair("message", message.toString()));

        //LOG
        System.out.println("Notifying devices with the following message \n \"" +message+ "\"");

        List<String> deviceIDsList = new ArrayList<String>();
        String [] deviceIDArray;

        //Get devices to notify
        List<JSONDeviceProfile> deviceList = getDevicesToNotify();

        for(JSONDeviceProfile device : deviceList) {
            deviceIDsList.add(device.getDeviceId());

            try {
                sender.send(message, device.getDeviceId(), 5);
            } catch (IOException e) {
                System.out.println("Error sending GCM message!");
                e.printStackTrace();
            }
        }
}

还有我的 Android onMessage 方法:

@Override
protected void onMessage(Context arg0, Intent intent) {

    String message = intent.getStringExtra("profile");

    Log.d(TAG + "Received Message: ", "Received Message: " + message.toString());

    //CALL NEW INTENT WITH PROFILE DETAILS
    Intent displayProfileIntent = new Intent(arg0, DisplayProfile.class);
    displayProfileIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    displayProfileIntent.putExtra("message", message); 
    startActivity(displayProfileIntent);

    /*
    //generateNotification(arg0, username);

    handler.post(new Runnable() {
        @Override
        public void run() {
            //Toast.makeText(getApplicationContext(), username, Toast.LENGTH_SHORT).show();

        }
    });
    */
}

我希望有人遇到过类似的问题,我只是想确认这个问题是我正在做的事情还是我无法控制。

tl;dr GCM 消息要么立即到达,要么大约 10 分钟后到达(延迟通常是一致的)。

最佳答案

客户端手机上的 GCM 框架部分在端口 5228 上使用 TCP 连接。此连接用于推送通知,但作为每个 TCP 连接,它可能会与某些路由器/运营商超时应用严格的策略来终止不活动的 tcp 连接(tcp idle timeout)。

例如,大多数 wifi 路由器会在 5 分钟后终止非 Activity 连接,就像我的一样。

GCM 框架使用keep-alive 机制在 wifi 上每 15 分钟发送一次心跳网络数据包,在 3G 上每 28 分钟发送一次。这种 keep-alive 并不总是对所有用户都可靠。

我在这里打开了谷歌的问题: https://productforums.google.com/forum/#!category-topic/nexus/connecting-to-networks-and-devices/fslYqYrULto 他们同意目前存在问题。

编辑(2014 年 1 月 8 日):目前 Google 将 wifi 和移动连接的心跳间隔更新为 8 分钟。这是一个影响所有 Android 设备 2.2+ 的远程更改 这是避免 tcp 推送连接超时的一个很好的改进。尽管如此,如果 wifi 路由器在 5 分钟后终止了非 Activity 连接,您将在推送通知中延迟 3 (8-5) 分钟(如果您没有其他通知保持连接有效)

编辑(2016 年 3 月 6 日):现在谷歌似乎正在测试我 2 年前的反馈,以建立一个动态机制来根据网络确定正确的心跳间隔。目前似乎是分阶段推出,据我所知仅适用于 wifi。因此,基于 wifi SSID,算法通过一种逐步细化来确定特定 wifi 的正确心跳间隔。这个很好听!这是一个远程更改,它会影响所有具有 Google Play 服务的安卓手机。

关于java - Google Cloud Messaging - 即时收到或延迟很长时间的消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16749038/

相关文章:

java - Selenium Webdriver 无法访问浏览器异常

java - 如何以任意顺序给出命令行参数?

android - ionic cordova run android 在上次更新后停止工作

android - 在 GCM 服务器上设置计划的推送通知

java - 在 XmlValidatingMessageSelector 中关闭 DTD 加载和验证

java - Spring 3.2/hibernate 4.1.9 : Use of @OneToMany or @ManyToMany targeting an unmapped class error

java - Android xml 文件突然显示 java 代码。

android - 如何以编程方式更改 android 工具栏中的图标?

android-studio - Android Studio 无法识别 InstanceID 类

android - GCMRegistrar checkManifest 使我的应用程序崩溃