您的位置:首页 > 移动开发 > Android开发

Android 电池电量监控初步

2013-09-13 15:25 337 查看

整体思路概览

①由于要显示电池图标,因此需要一组对应的小icon,程序算出当前电量之后,就在状态栏上显示对应的icon即可。本程序用到的icon已经提供在附件,下载后将里面的icons直接复制到res\drawable-hdpi中即可。

②由于电池更新是一个长期存在的过程,因此需要将我们的程序注册为系统服务,以便长期生存于Android系统中。

③服务不会自行启动,因此我们需要为自己的服务创建一个Activity,在第一次启动本程序的Activity时创建并启动我们的监控服务,之后的事便交由服务处理,Activity暂时未有太大作用(之后还可以在Activity中显示电池当前的各种基本属性等等,本文不作介绍),当然,我们也可以不要Activity,直接将我们的服务设置为开机启动即可,关于开机启动的事项已在Android开机启动Activity或Service的方法】一文中详细描述,恕不赘述。

④为了方便起见,应该制作本程序的桌面小工具,也就用到了AppWidget方面的知识,稍后一一道来。

分而治之

小麻雀的心脏——电池监控服务MonitorService

ACTION_BATTERY_CHANGED 的完整代码,我会在可能费解的地方批注,希望能帮助大家理解。

查看源码打印?

001
package
com.billhoo.study;
002
003
import
android.app.Notification;
//通知,即显示在屏幕左上角的小图标
004
import
android.app.NotificationManager;
005
import
android.app.PendingIntent;
006
import
android.app.Service;
007
import
android.content.BroadcastReceiver;
008
import
android.content.Context;
009
import
android.content.Intent;
010
import
android.content.IntentFilter;
011
import
android.os.BatteryManager;
012
import
android.os.IBinder;
013
014
public
class
MonitorService
extends

Service {
015
@Override
016
public
IBinder onBind(Intent intent) {
017
return
null
;
018
}
019
020
@Override
021
public
void
onStart(Intent intent,
int

startId) {
022
// 定义电池电量更新广播的过滤器,只接受带有ACTION_BATTERRY_CHANGED事件的Intent
023
IntentFilter batteryChangedReceiverFilter =
new

IntentFilter();
024
batteryChangedReceiverFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
025
026
// 向系统注册batteryChangedReceiver接收器,本接收器的实现见代码字段处
027
registerReceiver(batteryChangedReceiver,batteryChangedReceiverFilter);
028
029
// 实例化Notification通知的管理器,即字段notification manager
030
notifyManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
031
032
// 由于初始化本服务时系统可能没有发出ACTION_BATTERY_CHANGED广播,那么刚才注册的那个接收器将不会在本服务启动时被激活,这种情况下就无法显示当前电量,因此在这里添加一个匿名广播接收器。
033
new
BroadcastReceiver() {
034
@Override
035
public
void
onReceive(Context context,Intent intent) {
036
int
level = intent.getIntExtra(
"level"
,
0
);
//电池电量等级
037
int
scale = intent.getIntExtra(
"scale"
,
100
);
//电池满时百分比
038
int
status = intent.getIntExtra(
"status"
,
0
);
//电池状态
039
040
// 若正在充电
041
if
(status == BatteryManager.BATTERY_STATUS_CHARGING)

042
notification = getNotification(getChargingIcon(level *
100

/ scale),
043
"电池监控"
,System.currentTimeMillis(),
"电池电量"
,
"正在充电"
);
044
else
045
notification = getNotification(getStateIcon(level *
100

/ scale),
046
"电池监控"
,System.currentTimeMillis(),
"电池电量"
,
"请及时充电"
);
047
048
//向系统发送此通知,为方便起见,通知ID简单设为0
049
notifyManager.notify(
0
,notification);

050
}
051
};
052
}
053
054
@Override
055
public
void
onDestroy() {
056
//当本服务终止时,通过通知ID注销左上角的通知
057
notifyManager.cancel(
0
);
058
}
059
060
// --------------------------------------私有方法------------------------------
061
// 获得一个notification
062
private
Notification getNotification(
int

notificationIcon,String tickerText,
063
long
when,String contentTitle,String contentText) {

064
// 定义该notification的扩展文本和intent
065
Notification notification =
new
Notification(notificationIcon,tickerText,
066
when);
067
Context context = getApplicationContext();
068
Intent notificationIntent =
new
Intent(context,BatteryInfo.
class
);
069
PendingIntent contentIntent = PendingIntent.getActivity(
this
,
0
,
070
notificationIntent,
0
);
071
notification.setLatestEventInfo(context,contentTitle,contentText,

072
contentIntent);
073
074
// 设置本状态出现在“正在进行”而非“通知”栏目,不允许用户清除状态图标
075
notification.flags |= Notification.FLAG_ONGOING_EVENT;
076
return
notification;
077
}
078
079
// 获得对应的电池状态图标
080
private
int
getStateIcon(
int

batteryHealth) {
081
if
(batteryHealth >=
0
|| batteryHealth <=
100
)
082
return
batteryStateIcons[batteryHealth];
//这里是为了方便起见而硬编码的资源数组,直接从R.java文件中提取的十六进制资源ID
083
return
R.drawable.stat_sys_battery_unknown;
084
}
085
086
// 获得对应的充电状态图标
087
private
int
getChargingIcon(
int

batteryHealth) {
088
if
(batteryHealth >=
0
&& batteryHealth <
5
)
089
return
R.drawable.stat_sys_battery_charge_anim0;
090
if
(batteryHealth >=
5
&& batteryHealth <
10
)
091
return
R.drawable.stat_sys_battery_charge_anim01;

092
if
(batteryHealth >=
10
&& batteryHealth <
15
)
093
return
R.drawable.stat_sys_battery_charge_anim02;

094
if
(batteryHealth >=
15
&& batteryHealth <
20
)
095
return
R.drawable.stat_sys_battery_charge_anim03;

096
if
(batteryHealth >=
20
&& batteryHealth <
25
)
097
return
R.drawable.stat_sys_battery_charge_anim04;

098
if
(batteryHealth >=
25
&& batteryHealth <
30
)
099
return
R.drawable.stat_sys_battery_charge_anim05;

100
if
(batteryHealth >=
30
&& batteryHealth <
35
)
101
return
R.drawable.stat_sys_battery_charge_anim06;

102
if
(batteryHealth >=
35
&& batteryHealth <
40
)
103
return
R.drawable.stat_sys_battery_charge_anim07;

104
if
(batteryHealth >=
40
&& batteryHealth <
45
)
105
return
R.drawable.stat_sys_battery_charge_anim08;

106
if
(batteryHealth >=
45
&& batteryHealth <
50
)
107
return
R.drawable.stat_sys_battery_charge_anim09;

108
if
(batteryHealth >=
50
&& batteryHealth <
55
)
109
return
R.drawable.stat_sys_battery_charge_anim10;

110
if
(batteryHealth >=
55
&& batteryHealth <
60
)
111
return
R.drawable.stat_sys_battery_charge_anim11;

112
if
(batteryHealth >=
60
&& batteryHealth <
65
)
113
return
R.drawable.stat_sys_battery_charge_anim12;

114
if
(batteryHealth >=
65
&& batteryHealth <
70
)
115
return
R.drawable.stat_sys_battery_charge_anim13;

116
if
(batteryHealth >=
70
&& batteryHealth <
75
)
117
return
R.drawable.stat_sys_battery_charge_anim14;

118
if
(batteryHealth >=
75
&& batteryHealth <
80
)
119
return
R.drawable.stat_sys_battery_charge_anim15;

120
if
(batteryHealth >=
80
&& batteryHealth <
85
)
121
return
R.drawable.stat_sys_battery_charge_anim16;

122
if
(batteryHealth >=
85
&& batteryHealth <
90
)
123
return
R.drawable.stat_sys_battery_charge_anim17;

124
if
(batteryHealth >=
90
&& batteryHealth <
95
)
125
return
R.drawable.stat_sys_battery_charge_anim18;

126
if
(batteryHealth >=
95
&& batteryHealth <
100
)
127
return
R.drawable.stat_sys_battery_charge_anim19;

128
if
(batteryHealth ==
100
)

129
return
R.drawable.stat_sys_battery_charge_animfull;

130
return
R.drawable.stat_sys_battery_unknown;
131
}
132
133
// -------------------------------私有字段--------------------------------------
134
private
NotificationManager notifyManager =
null
;
135
private
Notification notification =
null
;
136
137
//这里是为了方便起见而硬编码的icon资源数组,直接从R.java文件中提取的十六进制资源ID,本数组的0号元素0x7f020002表示资源stat_sys_battery_0.png(见附件),以后累加。不同配置的ID可能不同,请读者自行修改。
138
private
int
batteryStateIcons[] = {
0x7f020002
,
0x7f020003
,
0x7f020004
,

139
0x7f020005
,
0x7f020006
,
0x7f020007
,
0x7f020008
,
0x7f020009
,

0x7f02000a
,
140
0x7f02000b
,
0x7f02000c
,
0x7f02000d
,
0x7f02000e
,
0x7f02000f
,

0x7f020010
,
141
0x7f020011
,
0x7f020012
,
0x7f020013
,
0x7f020014
,
0x7f020015
,

0x7f020016
,
142
0x7f020017
,
0x7f020018
,
0x7f020019
,
0x7f02001a
,
0x7f02001b
,

0x7f02001c
,
143
0x7f02001d
,
0x7f02001e
,
0x7f02001f
,
0x7f020020
,
0x7f020021
,

0x7f020022
,
144
0x7f020023
,
0x7f020024
,
0x7f020025
,
0x7f020026
,
0x7f020027
,

0x7f020028
,
145
0x7f020029
,
0x7f02002a
,
0x7f02002b
,
0x7f02002c
,
0x7f02002d
,

0x7f02002e
,
146
0x7f02002f
,
0x7f020030
,
0x7f020031
,
0x7f020032
,
0x7f020033
,

0x7f020034
,
147
0x7f020035
,
0x7f020036
,
0x7f020037
,
0x7f020038
,
0x7f020039
,

0x7f02003a
,
148
0x7f02003b
,
0x7f02003c
,
0x7f02003d
,
0x7f02003e
,
0x7f02003f
,

0x7f020040
,
149
0x7f020041
,
0x7f020042
,
0x7f020043
,
0x7f020044
,
0x7f020045
,

0x7f020046
,
150
0x7f020047
,
0x7f020048
,
0x7f020049
,
0x7f02004a
,
0x7f02004b
,

0x7f02004c
,
151
0x7f02004d
,
0x7f02004e
,
0x7f02004f
,
0x7f020050
,
0x7f020051
,

0x7f020052
,
152
0x7f020053
,
0x7f020054
,
0x7f020055
,
0x7f020056
,
0x7f020057
,

0x7f020058
,
153
0x7f020059
,
0x7f02005a
,
0x7f02005b
,
0x7f02005c
,
0x7f02005d
,

0x7f02005e
,
154
0x7f02005f
,
0x7f020060
,
0x7f020061
,
0x7f020062
,
0x7f020063
,

0x7f020064
,
155
0x7f020065
,
0x7f02007b
};

156
157
// 接受电池信息更新的广播
158
private
BroadcastReceiver batteryChangedReceiver =

new
BroadcastReceiver() {
159
public
void
onReceive(Context context,Intent intent) {
160
int
level = intent.getIntExtra(
"level"
,
0
);
161
int
scale = intent.getIntExtra(
"scale"
,
100
);
162
int
status = intent.getIntExtra(
"status"
,
0
);
163
164
// 若正在充电
165
if
(status == BatteryManager.BATTERY_STATUS_CHARGING)

166
notification = getNotification(getChargingIcon(level *
100

/ scale),
167
"Battery Monitor"
,System.currentTimeMillis(),
"电池电量"
,
"正在充电"
);
168
else
169
notification = getNotification(getStateIcon(level *
100

/ scale),
170
"Battery Monitor"
,System.currentTimeMillis(),
"电池电量"
,
"请及时充电"
);
171
notifyManager.notify(
0
,notification);

172
}
173
};
174
}

光有心,不跳怎么行?——BatteryMonitor

服务在系统配置文件中进行注册。

查看源码打印?

1
<!-- service -->
2
<
service
android:name
=
".MonitorService"

android:enabled
=
"true"
/>
Bill的另一篇文章【Android开机启动Activity或Service的方法】),下面,我们将在一个Activity中启动MonitorService服务。 在AndroidManifest.xml中进行注册

查看源码打印?

1
<!-- activity -->
2
<
activity
android:name
=
".BatteryMonitor"

android:label
=
"@string/battery_monitor_name"
>
3
<
intent-filter
>
4
<
action
android:name
=
"android.intent.action.MAIN"

/>
5
<
category
android:name
=
"android.intent.category.LAUNCHER"

/>
6
</
intent-filter
>
7
</
activity
>
中编码启动我们的MonitorService服务即可

查看源码打印?

01
package
com.billhoo.study;
02
03
import
android.app.Activity;
04
import
android.content.Intent;
05
import
android.os.Bundle;
06
07
08
public
class
BatteryMonitor
extends

Activity {
09
/** Called when the activity is first created. */
10
@Override
11
public
void
onCreate(Bundle savedInstanceState) {
12
super
.onCreate(savedInstanceState);
13
setContentView(R.layout.main);
14
15
//启动电池监控服务
16
startService(
new
Intent(
this
,MonitorService.
class
));
17
}
18
}
,看看左上角是不是出现了一个小电池图标,并显示着当前电量? 麻雀虽小,五脏俱全——MonitorWidgetProvider ,为麻雀穿上衣服 用户会将自己喜爱的小程序放在桌面以便快速启动,当然我们就不能放过这个机会! 还做不到这一点,难道我们应该期望用户在他的程序列表中长按我们的Activity,然后使出吃奶的劲儿把它扔在桌面上吗?不,他们通常长按桌面,然后轻点一个自己中意的Widget插件便能满足他们的需求。 ,一来方便用户查看电池状态(仅凭左上角的通知有时候并不能满足用户的需求),二来方便用户随时启动本程序附带的电池详细数据报告(本功能并未在本文中实现)。
本身就是一个广播接收器(BroadcastReceiver),因此我们最初企图直接用这个Widget接受ACTION_BATTERY_CHANGED广播并作出反应,但却发现这个接收器并不会接受电池更新的广播(不论我们在配置文件中配置与否)。所以只能另寻出路,我们想到,可以使用一个单独的为本Widget服务的Service,该Service检测到电池电量更新后就更新桌面的Widget显示。于是便有以下Widget及其配套Service的实现。 创建一个配置文件,用于描述本Widget在桌面显示时是个什么样子。

查看源码打印?

01
<!-- 项目路径\res\layout\monitor_widget_layout.xml -->
02
<?
xml
version
=
"1.0"

encoding
=
"utf-8"
?>
03
<
LinearLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
04
android:orientation
=
"vertical"
05
android:layout_width
=
"72dip"
06
android:layout_height
=
"72dip"
>

07
<
ImageView
android:id
=
"@+id/monitor_widget_view"
08
android:layout_width
=
"fill_parent"
09
android:layout_height
=
"fill_parent"
10
11
android:src
=
"@drawable/vertical_battery_unknown"

/>
12
</
LinearLayout
>
查看源码打印?

1
<!-- 项目路径\res\xml\monitor_widget_info.xml (xml文件夹是自行创建的)-->
2
<?
xml
version
=
"1.0"

encoding
=
"utf-8"
?>
3
<
appwidget-providerxmlns:androidappwidget-providerxmlns:android
=
"http://schemas.android.com/apk/res/android"

android:initialLayout
=
"@layout/monitor_widget_layout"
4
android:minWidth
=
"72dip"
android:minHeight
=
"72dip"

/>
配置文件中注册我们的Widget

查看源码打印?

1
<
receiver
android:name
=
".MonitorWidgetProvider"
>
2
<
intent-filter
>
3
<
action
android:name
=
"android.appwidget.action.APPWIDGET_UPDATE"

/>
4
<
action
android:name
=
"android.intent.action.BATTERY_CHANGED"

/>
5
</
intent-filter
>
6
<
meta-data
android:name
=
"android.appwidget.provider"
7
android:resource
=
"@xml/monitor_widget_info"

/>
8
</
receiver
>
的实现代码

查看源码打印?

01
package
com.billhoo.study;
02
03
import
android.appwidget.AppWidgetManager;
04
import
android.appwidget.AppWidgetProvider;
05
import
android.content.Context;
06
import
android.content.Intent;
07
08
public
class
MonitorWidgetProvider
extends

AppWidgetProvider
09
{
10
//当Widget第一次被启动时,启动配套服务
11
@Override
12
public
void
onEnabled(Context context) {

13
context.startService(
new
Intent(context,

14
15
WidgetUpdateService.
class
));
16
}
17
18
//当Widget更新时,启动配套服务
19
@Override
20
public
void
onUpdate(Context context,AppWidgetManager
21
22
appWidgetManager,
23
int
appWidgetIds[]) {
24
super
.onUpdate(context,appWidgetManager,appWidgetIds);

25
context.startService(
new
Intent(context,

26
27
WidgetUpdateService.
class
));
28
}
29
30
// 当桌面上这个widget的所有实体都被删除后,停止配套服务
31
@Override
32
public
void
onDisabled(Context context) {

33
context.stopService(
new
Intent(context,WidgetUpdateService.
class
));
34
}
35
}
编写配套的Service。
中注册这个服务。

查看源码打印?

1
<
service
android:name
=
".WidgetUpdateService"

android:enabled
=
"true"
/>
然后编写Java 代码:

查看源码打印?

001
package
com.billhoo.study;
002
003
import
android.app.Service;
004
import
android.appwidget.AppWidgetManager;
005
import
android.content.BroadcastReceiver;
006
import
android.content.ComponentName;
007
import
android.content.Context;
008
import
android.content.Intent;
009
import
android.content.IntentFilter;
010
import
android.os.BatteryManager;
011
import
android.os.IBinder;
012
import
android.widget.RemoteViews;
013
014
//用以根据电池电量更新而刷新桌面Widget的服务
015
public
class
WidgetUpdateService
extends

Service {
016
@Override
017
public
IBinder onBind(Intent intent) {
018
return
null
;
019
}
020
021
@Override
022
public
void
onStart(Intent intent,
int

startId) {
023
// 向系统注册电池电量更新广播,只接受带有ACTION_BATTERRY_CHANGED事件的Intent
024
registerReceiver(
this
.bCR,
new

IntentFilter(Intent.ACTION_BATTERY_CHANGED));
025
026
bCR =
new
BroadcastReceiver() {
027
@Override
028
public
void
onReceive(Context context,Intent intent) {
029
int
level = intent.getIntExtra(
"level"
,
0
);
030
int
scale = intent.getIntExtra(
"scale"
,
100
);
031
int
status = intent.getIntExtra(
"status"
,
0
);
032
int
batteryHealth = level *
100

/ scale;
033
int
icon =
0
;
034
035
AppWidgetManager widgetManager = AppWidgetManager.getInstance(context);
036
RemoteViews widgetView =
new
RemoteViews(context.getPackageName(),
037
R.layout.monitor_widget_layout);
038
039
// 若正在充电
040
if
(status == BatteryManager.BATTERY_STATUS_CHARGING) {

041
icon =getChargingIcon(batteryHealth);
042
widgetView.setImageViewResource(R.id.monitor_widget_view,icon  

043
044
);
045
}
else
046
widgetView.setImageViewResource(R.id.monitor_widget_view,
047
getStateIcon(batteryHealth));
048
widgetManager.updateAppWidget(
new
ComponentName(context,
049
MonitorWidgetProvider.
class
),widgetView);

050
}
051
};
052
}
053
054
private
BroadcastReceiver bCR =
null
;
055
056
// 获取电池状态图标
057
private
int
getStateIcon(
int

batteryHealth) {
058
if
(batteryHealth >=
0
|| batteryHealth <=
100
)
059
return
batteryStateIcon[batteryHealth /
5
];
060
return
R.drawable.vertical_battery_unknown;
061
}
062
063
// 获得对应的充电状态图标
064
private
int
getChargingIcon(
int

batteryHealth) {
065
if
(batteryHealth >=
0
&& batteryHealth <
5
)
066
return
R.drawable.vertical_charging_00;
067
if
(batteryHealth >=
5
&& batteryHealth <
10
)
068
return
R.drawable.vertical_charging_01;
069
if
(batteryHealth >=
10
&& batteryHealth <
15
)
070
return
R.drawable.vertical_charging_02;
071
if
(batteryHealth >=
15
&& batteryHealth <
20
)
072
return
R.drawable.vertical_charging_03;
073
if
(batteryHealth >=
20
&& batteryHealth <
25
)
074
return
R.drawable.vertical_charging_04;
075
if
(batteryHealth >=
25
&& batteryHealth <
30
)
076
return
R.drawable.vertical_charging_05;
077
if
(batteryHealth >=
30
&& batteryHealth <
35
)
078
return
R.drawable.vertical_charging_06;
079
if
(batteryHealth >=
35
&& batteryHealth <
40
)
080
return
R.drawable.vertical_charging_07;
081
if
(batteryHealth >=
40
&& batteryHealth <
45
)
082
return
R.drawable.vertical_charging_08;
083
if
(batteryHealth >=
45
&& batteryHealth <
50
)
084
return
R.drawable.vertical_charging_09;
085
if
(batteryHealth >=
50
&& batteryHealth <
55
)
086
return
R.drawable.vertical_charging_10;
087
if
(batteryHealth >=
55
&& batteryHealth <
60
)
088
return
R.drawable.vertical_charging_11;
089
if
(batteryHealth >=
60
&& batteryHealth <
65
)
090
return
R.drawable.vertical_charging_12;
091
if
(batteryHealth >=
65
&& batteryHealth <
70
)
092
return
R.drawable.vertical_charging_13;
093
if
(batteryHealth >=
70
&& batteryHealth <
75
)
094
return
R.drawable.vertical_charging_14;
095
if
(batteryHealth >=
75
&& batteryHealth <
80
)
096
return
R.drawable.vertical_charging_15;
097
if
(batteryHealth >=
80
&& batteryHealth <
85
)
098
return
R.drawable.vertical_charging_16;
099
if
(batteryHealth >=
85
&& batteryHealth <
90
)
100
return
R.drawable.vertical_charging_17;
101
if
(batteryHealth >=
90
&& batteryHealth <
95
)
102
return
R.drawable.vertical_charging_18;
103
if
(batteryHealth >=
95
&& batteryHealth <
100
)
104
return
R.drawable.vertical_charging_19;
105
if
(batteryHealth ==
100
)

106
return
R.drawable.vertical_battery_full;
107
return
R.drawable.stat_sys_battery_unknown;
108
}
109
110
private
int
batteryStateIcon[] = {
0x7f02007d
,
0x7f02007e
,
0x7f02007f
,

111
0x7f020080
,
0x7f020081
,
0x7f020082
,
0x7f020083
,
0x7f020084
,

0x7f020085
,
112
0x7f020086
,
0x7f020087
,
0x7f020088
,
0x7f020089
,
0x7f02008a
,

0x7f02008b
,
113
0x7f02008c
,
0x7f02008d
,
0x7f02008e
,
0x7f02008f
,
0x7f020090
,

0x7f020091
};
114
}
自带的电池图标了,何乐不为?

原文:http://www.open-open.com/lib//view/open1327829183952.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: