为什么安卓(6.0)系统在深度睡眠后约1小时禁止网络连接?

3
我在android的深度睡眠模式中遇到了问题,一个小时后出现了问题,这个问题只在Android6+中发生,在Android5以下没有出现过,因为没有设备,所以没有测试。 设备配置:
我有两个Android 6设备,Google Nexus 5和HTC One M9。这两个设备都配置为无SIM卡的WiFi模式,WiFi策略配置为始终开启(即使在睡眠模式下也是如此)。 情况:
我有一个唤醒广播接收器,它被注册到AlarmManager.ELAPSED_REALTIME_WAKEUP上,每当应用程序进入后台时,就会每2分钟触发一次。当应用程序暂停时,wifi锁被获取,并在应用程序回到前台时释放。
由于自Android KitKat起,AlarmManager.setRepeating(...)不准确,在Android 6上我使用AlarmManager.setWindow(...),窗口仅为1秒钟。每次接收器触发时,接收器(PendingIntent)会再次注册。
接收器的任务很简单。他只需要调用一个weburl(get请求)。成功请求后,wakelock被释放,如果超时或抛出异常也是如此。
在清单文件中,也存在WAKE_LOCK权限。
问题是:当我将应用程序置于后台(接收器变为启用状态)并关闭屏幕时,接收器每2分钟正确调用一次,但是大约1小时后,网络请求失败。
日志显示,接收器在1小时后也被调用,只是网络请求失败了。
源代码示例:
public class TestTools {
    private static final String LOG_TAG = TestTools.class.getSimpleName();

    public static String excuteGet(String targetURL) {
        try {
            URL obj = new URL(targetURL);
            HttpURLConnection con = (HttpURLConnection) obj.openConnection();
            con.setRequestMethod("GET");
            con.setConnectTimeout(10*1000);
            con.setReadTimeout(5*1000);

            int responseCode = con.getResponseCode();
            Log.d(LOG_TAG, "GET Response Code :: " + responseCode);

            if (responseCode == HttpURLConnection.HTTP_OK) { // success
                BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
                String inputLine;
                StringBuilder response = new StringBuilder();

                while ((inputLine = in.readLine()) != null) {
                    response.append(inputLine);
                }
                in.close();

                // print result
                Log.d(LOG_TAG, response.toString());

                return response.toString();
            } else {
                Log.d(LOG_TAG, String.format("GET request not worked (response code :: %s)", responseCode));
            }
        }
        catch (ProtocolException e) {
            Log.d(LOG_TAG, "ProtocolException: " + e.getMessage());
        }
        catch (MalformedURLException e) {
            Log.d(LOG_TAG, "MalformedURLException: " + e.getMessage());
        }
        catch (IOException e) {
            Log.d(LOG_TAG, "IOException: " + e.getMessage());
        }

        return null;
    }

}

public class Receiver extends WakefulBroadcastReceiver {
    @Override
    public void onReceive(final Context context, final Intent intent) {
        Log.d(LOG_TAG, "onReceive");

        final Thread test = new Thread(new Runnable() {
            @Override
            public void run() {
                TestTools.excuteGet("http://www.google.de/");
            }
        });
        test.start();

        try {
            test.join();
        } catch (InterruptedException e) {
            Log.d(LOG_TAG, e.getMessage());
        }

        // here the receiver is reregistered

        WakefulBroadcastReceiver.completeWakefulIntent(intent);
    }
}

你有想法出了什么问题以及如何解决吗?


更新:为了使应用程序在Android的待机模式下正常工作,您需要采用这个https://developer.android.com/training/monitoring-device-state/doze-standby.html#assessing_your_app

1个回答

6

但是大约1小时后,网络请求失败了

可以推测设备进入了Doze模式

你有什么想法出了问题吗?

从用户和Android的角度来看,没有任何问题。一切都按预期运行。

请理解,Doze模式是专门为了防止开发人员做你正在尝试做的事情而添加的。每两分钟进行一次网络I/O对电池寿命非常不利。太多的开发人员不关心用户和他们的电池,因此Android正在剥夺这些开发人员的控制权,以帮助用户。

如何解决?

在很大程度上,没有什么需要解决的。再次强调,一切都按照规格运作。您可能需要调整您的期望值。

现在,如果用户认为应用需要消耗更多电池电量,则可以将其添加到电池优化白名单中。此操作位于“设置”>“应用程序”>(操作栏中的齿轮图标)>“忽略电池优化”中。任何已设置“忽略电池优化”的应用都会更像早期设备。
同时,用户也可以将设备连接到充电器上;当设备正在充电时,它不会进入Doze模式。

1
感谢您的回答。取消电池优化应该可以解决我的问题。为了您的兴趣:为什么我需要每2分钟访问一次网络? 好的,我只需要每10分钟进行2次网络访问,因为我正在开发一个VoIP(SIP)应用程序,而sip注册器强制最大注册超时时间为10分钟。所以我需要每10分钟重新注册一次。 每10分钟2次访问,因为如果一个重新注册失败,第二个重新注册应该会成功。 - Philipp S.
1
要使应用程序在Android Doze模式下工作,您需要采用此方案:https://developer.android.com/training/monitoring-device-state/doze-standby.html#assessing_your_app - Philipp S.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接