【问题标题】:Checking battery level in the background with a service使用服务在后台检查电池电量
【发布时间】:2014-07-02 13:50:48
【问题描述】:

我搜索了很多,但我总是比较困惑。

我必须创建一个在后台运行并检查电池电量的应用。如何创建服务? Service 应该在设备启动时启动,并且必须在电池达到一定百分比时与 Activity 通信,因此没有来自消费者的任何交互。

我要创建什么类型的服务?我必须做些什么?

【问题讨论】:

  • 您需要添加“启动时运行”权限,然后设置一个广播接收器来监听手机启动时发生的特定意图。该广播接收器将启动服务意图。然后在该服务中,使用 android 的 BatteryManager 来检查电池电量。
  • 感谢您的建议

标签: android service background-process battery


【解决方案1】:

与其使用长时间运行的服务,不如使用 AlarmManager 定期触发警报,这可以由 BroadcastReceiver 接收,并可以调用 Service(它应该在某个时候自行停止)或 IntentService 来执行电池检查。这将给用户带来最小的痛苦,因为它将使用更少的资源来让您的应用程序执行它需要做的事情,并且对您来说更少的痛苦,因为系统不太可能杀死您无休止地运行的应用程序。

例如,对于警报接收器:

public class AlarmReceiver extends BroadcastReceiver {
    private static final String TAG = "AlarmReceiver";
    private static final int REQUEST_CODE = 777;
    public static final long ALARM_INTERVAL = DateUtils.MINUTE_IN_MILLIS;


    // Call this from your service
    public static void startAlarms(final Context context) {
        final AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        // start alarm right away
        manager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, 0, ALARM_INTERVAL,
                getAlarmIntent(context));
    }

    /*
     * Creates the PendingIntent used for alarms of this receiver.
     */
    private static PendingIntent getAlarmIntent(final Context context) {
        return PendingIntent.getBroadcast(context, REQUEST_CODE, new Intent(context, AlarmReceiver.class), PendingIntent.FLAG_UPDATE_CURRENT);
    }

    @Override
    public void onReceive(final Context context, final Intent intent) {
        if (context == null) {
            // Somehow you've lost your context; this really shouldn't happen
            return;
        }
        if (intent == null){
            // No intent was passed to your receiver; this also really shouldn't happen
            return;
        }
        if (intent.getAction() == null) {
            // If you called your Receiver explicitly, this is what you should expect to happen
            Intent monitorIntent = new Intent(context, YourService.class);
            monitorIntent.putExtra(YourService.BATTERY_UPDATE, true);
            context.startService(monitorIntent);
        }   
     }
}

对于您的引导接收器:

public class BootReceiver extends BroadcastReceiver{
    private static final String TAG = "BootReceiver";
    private static final String ACTION_BOOT = "android.intent.action.BOOT_COMPLETED";

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equalsIgnoreCase(ACTION_BOOT)) {
            // This intent action can only be set by the Android system after a boot
            Intent monitorIntent = new Intent(context, YourService.class);
            monitorIntent.putExtra(YourService.HANDLE_REBOOT, true);
            context.startService(monitorIntent);
        }
    }
}

为了您的服务:

public class YourService extends Service {
    private static final String TAG = "YourService";
    public static final String BATTERY_UPDATE = "battery";

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

        if (intent != null && intent.hasExtra(BootReceiver.ACTION_BOOT)){
            AlarmReceiver.startAlarms(YourService.this.getApplicationContext());
        }
        if (intent != null && intent.hasExtra(BATTERY_UPDATE)){
            new BatteryCheckAsync().execute();
        }

        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }


    private class BatteryCheckAsync extends AsyncTask<Void, Void, Void>{

        @Override
        protected Void doInBackground(Void... arg0) {
            //Battery State check - create log entries of current battery state
            IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
            Intent batteryStatus = YourService.this.registerReceiver(null, ifilter);

            int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
            boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
                             status == BatteryManager.BATTERY_STATUS_FULL;
            Log.i("BatteryInfo", "Battery is charging: " + isCharging);

            int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
            int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
            Log.i("BatteryInfo", "Battery charge level: " + (level / (float)scale));
            return null;
        }

        protected void onPostExecute(){
            YourService.this.stopSelf();
        }
    }
}

在您的清单中,您需要添加:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

    <!-- Services -->
    <service
        android:name="com.your.package.YourService"
        android:enabled="true"
        android:exported="false"
        android:label="@string/app_name" >
    </service>

    <!-- Receivers -->
    <receiver
        android:name="com.your.package.AlarmReceiver"
        android:enabled="true" />
    <receiver
        android:name="com.your.package.BootReceiver"
        android:enabled="true"
        android:exported="true" >
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>

【讨论】:

  • BatteryCheckAsync 存在问题。需要扩展 AsyncTask,doInBackground 需要返回 true 才能调用 protected void onPostExecute(Boolean result)。
  • @WalkingFood。这仍然是 2018 年的良好做法吗?还是有更好的方法?
【解决方案2】:

您不需要服务。在您的应用程序中包含一个广播接收器,用于侦听 Intent.ACTION_BATTERY_CHANGED 广播。在您的应用程序清单中定义广播接收器,它会在电池状态发生变化时自动启动。

广播包含有关电池当前状态的信息,因此无需精心设计(而且非常昂贵!)的解决方案来轮询此信息。

This page 将提供所有详细信息。

来自该页面的有趣引述:

您无法轻松地持续监控电池状态,但您不会 需要。

一般来说,不断监测电池的影响 水平对电池的影响比您的应用程序的正常水平更大 行为,因此最好只监控显着变化 电池电量——特别是当设备进入或退出低电量时 电池状态。

下面的manifest sn-p是从intent filter元素中提取的 在广播接收器中。接收器被触发,每当 设备电池变低或通过监听退出低状态 ACTION_BATTERY_LOW 和 ACTION_BATTERY_OKAY。

<receiver android:name=".BatteryLevelReceiver">
<intent-filter>
  <action android:name="android.intent.action.ACTION_BATTERY_LOW"/>
  <action android:name="android.intent.action.ACTION_BATTERY_OKAY"/>
  </intent-filter>
</receiver>

您可能希望监控的其他操作包括:ACTION_BATTERY_CHANGEDACTION_POWER_CONNECTEDACTION_POWER_DISCONNECTED

【讨论】:

  • 但我只想第一次打开应用程序,它必须整天在后台运行
  • 安卓!= Windows。您需要了解应用程序如何运行的新模型。如果您“整天在后台运行”,那么您的应用程序就是“打开的”。它可能对用户没有任何可见的存在,因为是否启动 Activity 是您的选择——您应该做出选择的地方是在广播接收器中。阅读我链接到的页面!
  • @DaleWilson 无法按照您的建议在 AndroidManifest.xml 中注册 Intent.ACTION_BATTERY_CHANGED,因为 ACTION_BATTERY_CHANGED 是一种粘性意图,因此无法在 AndroidManifest.xml 中声明。来源 (developer.android.com/reference/android/content/…)。你知道任何其他可行的方法吗?
  • 嗯.. 看起来他们不会让你“永久”为 ACTION_BATTERY_CHANGED 注册一个监听器。我猜这是因为这是一个坏主意——它会对你的电池寿命产生不利影响!但是,如果您仍想尝试,请为 ACTION_BOOT_COMPLETED 注册一个侦听器,并让该侦听器为 ACTION_BATTERY_CHANGED 注册侦听器。 [检查这是否会降低您的电池寿命!]
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多