长时间运行的服务消耗大量电池

时间:2013-08-11 09:23:19

标签: android android-service android-sensors android-broadcast

我开发了一个应用程序,有些人抱怨它需要太多电池,这是屏幕后第二大消耗过程。但是,在某些设备中,它不会消耗那么多电池。

我的应用所做的所有工作都在服务中。该服务是粘性的并且一直在运行(android系统可能在资源较少时将其杀死或在设备进入休眠状态时暂停),只要屏幕打开就有监听加速度计,它不是前台服务并没有举行唤醒锁。

有人可以告诉我为什么需要大量电池吗? 为什么这只发生在某些设备上?

以下是相关代码:

public class aListenerService extends Service implements SensorEventListener
{
    private BroadcastReceiver mScreenReceiver = new BroadcastReceiver()
    {
        // if screen was turned on then register to accelerometer
        // if screen was turned off then unregister from accelerometer
    }

    private BroadcastReceiver mPhoneStateReceiver = new BroadcastReceiver()
    {
        // do something...
    }

    @Override
    public void onCreate() 
    {
        super.onCreate();

        // get sensor manager and accelerometer sensor
        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

        // register accelerometer sensor and receiver
        mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
        IntentFilter screenFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
        screenFilter.addAction(Intent.ACTION_SCREEN_ON);
        registerReceiver(mScreenReceiver, screenFilter);
        registerReceiver(mPhoneStateReceiver, new IntentFilter(INTENT_ACTION_PHONE_STATE));
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) 
    {
        super.onStartCommand(intent, flags, startId);

        return Service.START_STICKY;
    }

    @Override
    public void onDestroy() 
    {
        super.onDestroy();

        // unregister to sensor and receivers
        mSensorManager.unregisterListener(this);
        unregisterReceiver(mScreenReceiver);
        unregisterReceiver(mPhoneStateReceiver);
    }

    @Override
    public void onSensorChanged(SensorEvent event)
    {
        // do something...
    }
}

1 个答案:

答案 0 :(得分:6)

关于CPU和电池,一直运行服务可能很昂贵 - 这是服务的缺点之一。特别是如果包含导致某些CPU负载的线程。有一些选项可供选择,具体取决于您的应用程序要求:

  1. 如果您的服务结果仅在用户可以使用它时相关,您可能会想到在屏幕上开启和关闭事件停止和启动服务 - 或者至少启动和停止包含的线程/处理程序。这可以通过使用BroadcastReceiver

    来完成
    public class ScreenReceiver extends BroadcastReceiver {
    
      @Override
      public void onReceive(Context context, Intent intent) {
          if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
              // (1) stop service or (2) stop all threads and unregister all event 
              // handlers, if the service has to register the screen receiver
          } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
              // (1) start service or (2) start all threads and register all event
              // handlers as needed
          }
      }
    }
    

    请注意,必须以编程方式注册屏幕事件。如果您必须在同一服务内部注册屏幕开启和关闭事件,请将其作为 sticky 启动。这样就可以保留服务实例。 (示例:电池小部件,天气信息......)

  2. 如果您拥有基于事件的环境,则可以考虑使用Google Cloud Messaging(GCM)。使用GCM,您可以从任何服务器向任何已注册的设备发送消息,使其唤醒并处理传入的信息。无需一直轮询信息。

    查看Google官方documentation和示例,如果此方案符合您的要求(示例:短信应用,聊天应用,...)

  3. 如果您需要定期处理/运行数据/代码,您可能会考虑使用AlarmManager

    public void SetAlarm(Context context) {
      AlarmManager manager = (AlarmManager)context.
                              getSystemService(Context.ALARM_SERVICE);
    
      Intent intent = new Intent(context, AlarmManagerBroadcastReceiver.class);
      PendingIntent pendingIntent = 
                    PendingIntent.getBroadcast(context, 0, intent, 0);
    
      am.setRepeating(AlarmManager.RTC_WAKEUP, 
                      System.currentTimeMillis(), 1000 *60 , pendingIntent);
    }
    

    然而,缺点是它不适合短时间间隔(比方说小于30分钟)。 (示例:电子邮件客户端,...)

  4. 所以有一些替代方案。看看你的代码我可以看到你正在用传感器做些什么。如果屏幕关闭,您是否需要传感器信息?或者什么样的事件可以触发服务的开始和结束?

    如果你真的需要结果(例如GPS跟踪器),你可能别无选择,只能优化你的代码。如果电池电量不足,停止服务可能有意义(详见this)。

    祝你好运!