在广播接收器响应Intent.ACTION_BATTERY_CHANGED之前获取电池级别

42

我在我的程序中有一个广播接收器来获取电池电量的反应,如下所示:

private BroadcastReceiver mBatInfoReceiver = new BroadcastReceiver(){
    @Override
    public void onReceive(Context arg0, Intent intent) {
        int level = intent.getIntExtra("level", 0);
        // do something...
    }
}

    registerReceiver(this.mBatInfoReceiver, 
            new IntentFilter(Intent.ACTION_BATTERY_CHANGED));

然而,这段代码必须等待电池状态更新,因此如果您有一个基于电池水平设置的GUI元素,则必须等待电池事件发生。是否有一种方法可以推动它开始工作,或者仅运行一些代码以查看上次广播时的电池电平?

6个回答

84

以下是一种不需要注册广播接收器即可获取电池电量的方法:

Intent batteryIntent = context.getApplicationContext().registerReceiver(null,
                    new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
int rawlevel = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
double scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
double level = -1;
if (rawlevel >= 0 && scale > 0) {
    level = rawlevel / scale;
}

由于广播消息的黏性特性,它可以使用空的BroadcastReceiver。

如果您在意图接收器中并出现异常,则使用getApplicationContext()技巧:

android.content.ReceiverCallNotAllowedException: 不允许IntentReceiver组件注册以接收意图


在某些情况下(例如在系统服务中运行),getApplicationContext() 将返回 null。在这种情况下,调用应该是: context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); - hemisphire
1
@hemisphire写道:“在某些情况下(比如运行在系统服务中),getApplicationContext()将返回null”。我不认为这总是正确的。也许这取决于服务的类型。 - Tom
1
太好了!现在我可以不用服务来完成它。 - thecr0w
1
我非常确定这是在BroadcastReceiver中获取电池信息的唯一方法,而不会出现ReceiverCallNotAllowedException异常。感谢有用的提示! :) - Xanatos

37

有没有办法推动它工作或者运行一些代码以查看上次广播时的电池电量?

你可以使用你的IntentFilter和一个nullBroadcastReceiver调用registerReceiver()来获取最后一次广播的Intent。这是可行的,因为ACTION_BATTERY_CHANGED被称为"粘性广播",我在这个StackOverflow问答中更详细地描述了它。


3
我在问题中提到的接收器实际上是在创建后立即被调用,只是我没有注意到这一点,因为我在之后重新初始化了变量。 - stealthcopter
获取下面描述的applicationContext来进行调用会引起问题吗?我遇到了这样的问题,即使我传入null,我的广播接收器也不被允许注册意图。那么这个问题的正确解决方案是什么? - Cheryl Simon
6
getApplicationContext()在这里应该是可以的,特别是如果你正在尝试从一个BroadcastReceiver中执行此操作。 - CommonsWare

6
    public static String batteryLevel(Context context)
    {
        Intent intent  = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));   
        int    level   = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
        int    scale   = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100);
        int    percent = (level*100)/scale;
        return String.valueOf(percent) + "%";
    }

2
// Put this Code into your MainActivity

private BroadcastReceiver mBatInfoReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context c, Intent i) {
        int level = i.getIntExtra("level", 0);
        ProgressBar pb = (ProgressBar) findViewById(R.id.progressbar);
        pb.setProgress(level);
        TextView tv = (TextView) findViewById(R.id.textfield);
        tv.setText("Battery Level: " + Integer.toString(level) + "%");
    }

};

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    registerReceiver(mBatInfoReceiver, new IntentFilter(
            Intent.ACTION_BATTERY_CHANGED));
}

我需要在onPause中注销此接收器吗?我已经注销了,但这会导致错误01-11 15:08:21.711:E/AndroidRuntime(31730):Caused by: java.lang.IllegalArgumentException:未注册接收器:com.example.batterylevel.ChargeActivity$1@426304a0。 - user3233280

1
我使用这种方法来获取电池的电量水平,而无需接收更新。
public float getMyBatteryLevel() {
        Intent batteryIntent = this.getApplicationContext().registerReceiver(null,
        new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
        return batteryIntent.getIntExtra("level", -1);
}

0
请注意,您从registerReceiver调用中获得的意图。
Intent intent  = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));

可能为空。因此在使用意图之前,请进行检查,例如:

if(intent != null){ 
// do your stuff here... 
}

我刚刚遇到了一个空指针异常,导致应用程序崩溃了!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接