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

adl*_*adl 8 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...
    }
}
Run Code Online (Sandbox Code Playgroud)

Tri*_*mon 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
          }
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)

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

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

    查看Googles 文档和示例,如果此方案符合您的要求(示例:消息传递应用程序,聊天应用程序,......)

  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);
    }
    
    Run Code Online (Sandbox Code Playgroud)

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

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

如果您确实一直需要结果(例如GPS跟踪器),那么除了优化代码之外,您可能别无选择.可能是有意义的停止服务,如果电池电量低(见有详细介绍).

祝好运!