Android:关闭“永远在线”时报警后后台线程中的连接问题

时间:2011-05-09 19:04:23

标签: android polling alarm android-alarms

问题描述:

在我的Android应用程序中,我在进行远程HTTP时会遇到连接问题 (“轮询”)来自警报响起后启动的AsyncTask。

当标准Android设置“启用永远在线时,查找效果非常好 移动数据“(设置 - >无线和网络 - >移动网络)已启用 “on”

解决方案有效:警报响起,Android“服务”收到警报意图, 启动后台线程(AsyncTask)。新线程获得部分唤醒 锁定,建立连接(轮询),通知用户并释放 唤醒锁。

到目前为止,这么好。问题是,当永远在线“关闭”时,轮询会在大部分时间失败,如果 手机处于待机状态一段时间(> 30分钟)。

由于轮询线程发送通知,我直接得到反馈 不成功的投票尝试。

动机:

许多用户开启“永远在线”以减少电池消耗。所以,很可能 该应用用户遇到问题。我想处理或防止用户将面临的“错误”。

解决方案尝试:

我经历了很多实验而没有任何重大突破:

  • 多次重试和中间休眠以给手机一些时间来建立连接
  • http参数(超时等)
  • 不同的HttpClient(Apache)

问题:

  • 完全设置“永远在线”是什么意思?开发人员必须考虑什么?
  • 我想知道是否一般可以实现一个基于警报的轮询机制,即使“永远在线”,也可以建立数据连接 转身“关闭”。
  • 是否有替代解决方案(无法使用C2DM)?

更新

似乎并非所有Android设备都具有“永远在线”设置。它似乎是设备,或者更可能是提供者依赖的。

2 个答案:

答案 0 :(得分:0)

如果您打算实施实时通信协议,并尝试使用短期轮询,这可能会以类似的体验解决问题:

我们的应用程序有类似的要求,并注意到一些事项:

  1. 并非每个网络都具有“启用永远在线移动数据”首选项。我在使用DroidX的Verizon上,此选项不在菜单中。数据始终开启。

  2. 与您的想法相反,即使您没有部分唤醒锁定,当手机进入睡眠状态时,套接字也不会被杀死。当手机进入睡眠状态时,您的应用程序会停止接收广播事件(例如,连接更改事件),因此您不能依赖Android操作系统在临时断开数据连接时告诉您。不要进行报警轮询,而是考虑使用Keep-Alive发送HTTP请求的长轮询,并且无限期地保持连接打开,直到得到响应。

  3. 阻止套接字读取操作不会抛出IOException,EOFException,或者在丢弃信号时抛出其他信息,因此您需要有一个单独的线程定期检查网络状态。最简单的方法是使用NetworkInterface类并构建如下内容:

  4. private OnCheckNetworkConnectivity networkConnectivityCallback = new OnCheckNetworkConnectivity() {
            String ipAddress;
    
            public boolean isConnected() {
                String newIpAddress = getLocalIpAddress();
                if(newIpAddress != null) {
                if(ipAddress == null) {
                    ipAddress = newIpAddress;
                    return true;
                }
                if(!newIpAddress.equals(ipAddress)) {
                    ipAddress = newIpAddress;
                    return false;
                }
    
                // still the same IP address, we should still have the same connection
                return true;
                }
    
                ipAddress = null;
                return false;
            }
    
            public String getLocalIpAddress() {
                try {
                    for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
                        NetworkInterface intf = en.nextElement();
                        for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
                            InetAddress inetAddress = enumIpAddr.nextElement();
                            if (!inetAddress.isLoopbackAddress()) {
                                return inetAddress.getHostAddress();
                            }
                        }
                    }
                } catch (SocketException ex) {
                return null;
                }
                return null;
            }
        };
    

答案 1 :(得分:0)

如果您使用的是AlarmManager,它应该唤醒设备。

我想知道在手机被唤醒之后,你是否正试图过快地建立连接,然后才有机会确保连接。

考虑:

检查AlarmManager接收器中的连接。如果没有连接,那么:

在从AlarmManager接收器返回之前,启动一个单独的线程。在帖子中:

  1. 获取唤醒锁
  2. 注册CONNECTIVITY_CHANGE的广播接收器
  3. 等待一段合理的时间以便成功连接(由广播接收器事件指示)。
  4. 如果时间到期,请释放唤醒锁定并停止线程,手机将重新进入睡眠状态。
  5. 尝试在收到CONNECTIVITY_CHANGE广播接收器的事件后才建立连接。