轮询服务:不定期

Posted

技术标签:

【中文标题】轮询服务:不定期【英文标题】:Polling service: irregular intervals 【发布时间】:2013-12-06 14:20:16 【问题描述】:

出于测试目的,我制作了一个由简单活动组成的小型 android 应用程序,您可以在其中插入主机、端口和间隔(以秒为单位)。该应用程序启动一个服务,该服务创建一个线程,该线程的循环从套接字的输入流中读取,直到它被有意停止。 这是服务的代码:

@Override
public int onStartCommand(Intent intent, int flags, int startId) 


    prepareFileLogging();

    FILELOG.info("PollingService: onStartCommand");

    mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    Intent bIntent = new Intent(this, MainActivity.class);
    PendingIntent pbIntent = PendingIntent
            .getActivity(this, 0, bIntent, Intent.FLAG_ACTIVITY_CLEAR_TOP);
    Notification.Builder bBuilder =
            new Notification.Builder(this)
                    .setSmallIcon(android.R.drawable.stat_notify_sync)
                    .setContentTitle("PollingTest")
                    .setContentText("Servizio di polling attivo")
                    .setAutoCancel(true)
                    .setOngoing(true)
                    .setContentIntent(pbIntent);

    this.startForeground(1, bBuilder.build());

    Log.i("PollingService", "Received start id " + startId + ": " + intent);

    FILELOG.info("PollingService: Received start id " + startId + ": " + intent);


    hostName = intent.getExtras().getString(PAR_HOST);
    portNumber = intent.getExtras().getInt(PAR_PORT);
    freqSeconds = intent.getExtras().getInt(PAR_FREQ);


    if(pollingThread == null)

        FILELOG.info("pollingThread not running: starting...");

        pollingThread = new Poll();
        pollingThread.start();


    



    Toast.makeText(this, "Servizio in Background: Serviziosincronizzazione.onCreate()",
            Toast.LENGTH_LONG).show();

    mReceiver = new BroadcastRec();

    getApplication().registerReceiver(mReceiver, filter);


    return START_REDELIVER_INTENT;






@Override
public void onDestroy() 

    mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    Notification.Builder bBuilder = new Notification.Builder(this)
            .setSmallIcon(android.R.drawable.stat_notify_error).setContentTitle(
                    "PollingTest")
            .setContentText("Il Servizio di polling è sinterrotto");

    Toast.makeText(this, "Servizio interrotto", Toast.LENGTH_SHORT).show();

    getApplication().unregisterReceiver(mReceiver);

    stopPollingService();
    Log.i("PollingService", "onDestroy");

    super.onDestroy();




private class Poll extends Thread 

    @Override
    public void run() 

        Thread thisThread = Thread.currentThread();

        FILELOG.info("pollingThread: started");

        try 

            Socket echoSocket = new Socket(hostName, portNumber);

            PrintWriter out =
                    new PrintWriter(echoSocket.getOutputStream(), true);
            BufferedReader in =
                    new BufferedReader(
                            new InputStreamReader(echoSocket.getInputStream()));


            int nanos = 250000;

            while (pollingThread == thisThread) 

                Log.i("PollThread", "start of a new call");

                out.println("prova");
                String response = in.readLine();
                FILELOG.info("pollingThread: server response: " +response);

                System.out.println("server: " + response);

                if (response != null && response.equals("null")) 
                    FILELOG.info("pollingThread: server down (reponse 'null'), new socket");

                    echoSocket = new Socket(hostName, portNumber);
                


                sendBroadcast(new Intent());

                try 
                    Log.i("PollThread", "timeout start...");
                    Thread.sleep(freqSeconds*1000, nanos);
                 catch (InterruptedException e) 
                    Log.i("PollThread", e.getMessage());
                    FILELOG.info("pollingThread error: " + e.getMessage());
                
            


         catch (UnknownHostException e) 
            FILELOG.info("pollingThread error: Don't know about host " + e.getMessage());

            System.err.println("Don't know about host " + hostName);
            stopPollingService();

         catch (IOException e) 
            FILELOG.info("pollingThread error: Couldn't get I/O for the connection to " + e.getMessage());
            System.err.println("Couldn't get I/O for the connection to " +
                    hostName);
            stopPollingService();


        


    

我让应用程序在平板电脑上运行了一天,分析了电池的消耗情况以及两次向服务器发出请求的时间间隔。 我注意到的问题是,大约 10 分钟,5 秒的间隔得到遵守,然后它在 5 到 20 秒之间变化! 平板电脑已被唤醒几次并解锁,服务从未崩溃。 这是服务器观察到的间隔序列:

有人能想到为什么会这样吗?

【问题讨论】:

我认为您的服务正在被系统破坏,然后以不规则的时间间隔重新启动,因为您正在从 onStartCommand 发送重新交付意图常量。你说服务器没有崩溃,但是 onDestroy 曾经被调用过吗? onDestroy 永远不会被调用,而 onStartCommand 只会被调用一次! 【参考方案1】:

系统很可能会进入低功耗状态,因为设备空闲了 10 分钟。为了可靠地唤醒您,您需要通过AlarmManager 使用闹钟或保持部分唤醒锁定。

【讨论】:

但是平板被唤醒了两三遍! 可能是您的设备进入睡眠状态并暂停其网络连接,然后唤醒并再次连接(即 wifi)。这可能会使您的套接字通信“涓涓细流”,因此您的in.readLine() 呼叫不会立即发生并导致延迟。在这种情况下,直到你得到一个完整的行,你的 5 秒超时才会发生。 你知道高级设置:“Wifi优化”是什么吗?也许是相关的。 根据我的经验,当进入低功耗状态时,平台对其各种硬件组件(例如 wifi)的处理往往取决于供应商。话虽如此,较新版本的 Android 中提供的“Wifi 优化”功能会在屏幕关闭时通过让硬件长时间休眠来降低 wifi 性能。所以是的,这很可能与您所看到的行为有关。 谢谢!我将在关闭此设置的情况下进行另一次测试

以上是关于轮询服务:不定期的主要内容,如果未能解决你的问题,请参考以下文章

如何在 iOS 中使用 AFNetworking 从 REST 接口定期轮询/拉取

使用SqlDependency与表的定期轮询(对性能的影响)

长轮询和服务器行为

定期轮询具有大量文件的 AWS S3 存储桶中的新文件?

如何定期更新 Ember 的模型(例如在 setInterval 中)?

如何在backbone.js 中进行轮询?