8

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

我的应用程序所做的所有工作都在服务中。该服务是粘性的并且一直在运行(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...
    }
}
4

1 回答 1

8

在 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 的文档和示例(示例:消息传递应用程序、聊天应用程序......)

  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 分钟)不是一个好的选择。(示例:电子邮件客户端,...)

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

如果您真的一直需要结果(例如 GPS 跟踪器),您可能别无选择,只能优化您的代码。如果电池电量不足,停止服务可能是有意义的(有关更多详细信息,请参阅内容)。

祝你好运!

于 2013-08-11T12:27:34.953 回答