Android 电池电量监控初步

整体思路概览

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

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

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

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

分而治之

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

ACTION_BATTERY_CHANGED    的完整代码,我会在可能费解的地方批注,希望能帮助大家理解。  
001package com.billhoo.study; 
002
003import android.app.Notification;  //通知,即显示在屏幕左上角的小图标 
004import android.app.NotificationManager; 
005import android.app.PendingIntent; 
006import android.app.Service; 
007import android.content.BroadcastReceiver; 
008import android.content.Context; 
009import android.content.Intent; 
010import android.content.IntentFilter; 
011import android.os.BatteryManager; 
012import android.os.IBinder; 
013
014public class MonitorService extends Service { 
015@Override
016public IBinder onBind(Intent intent) { 
017return null
018
019
020@Override
021public void onStart(Intent intent, int startId) { 
022// 定义电池电量更新广播的过滤器,只接受带有ACTION_BATTERRY_CHANGED事件的Intent 
023IntentFilter batteryChangedReceiverFilter = new IntentFilter(); 
024batteryChangedReceiverFilter.addAction(Intent.ACTION_BATTERY_CHANGED); 
025
026// 向系统注册batteryChangedReceiver接收器,本接收器的实现见代码字段处 
027registerReceiver(batteryChangedReceiver, batteryChangedReceiverFilter); 
028
029// 实例化Notification通知的管理器,即字段notification manager 
030notifyManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); 
031
032// 由于初始化本服务时系统可能没有发出ACTION_BATTERY_CHANGED广播,那么刚才注册的那个接收器将不会在本服务启动时被激活,这种情况下就无法显示当前电量,因此在这里添加一个匿名广播接收器。 
033new BroadcastReceiver() { 
034@Override
035public void onReceive(Context context, Intent intent) { 
036int level = intent.getIntExtra("level", 0);  //电池电量等级 
037int scale = intent.getIntExtra("scale", 100);  //电池满时百分比 
038int status = intent.getIntExtra("status", 0);  //电池状态 
039
040// 若正在充电 
041if (status == BatteryManager.BATTERY_STATUS_CHARGING) 
042notification = getNotification(getChargingIcon(level * 100 / scale), 
043"电池监控", System.currentTimeMillis(), "电池电量", "正在充电"); 
044else
045notification = getNotification(getStateIcon(level * 100 / scale), 
046"电池监控", System.currentTimeMillis(), "电池电量", "请及时充电"); 
047
048//向系统发送此通知,为方便起见,通知ID简单设为0 
049notifyManager.notify(0, notification); 
050
051}; 
052
053
054@Override
055public void onDestroy() { 
056//当本服务终止时,通过通知ID注销左上角的通知 
057notifyManager.cancel(0); 
058
059
060// --------------------------------------私有方法------------------------------ 
061// 获得一个notification 
062private Notification getNotification(int notificationIcon, String tickerText, 
063long when, String contentTitle, String contentText) { 
064// 定义该notification的扩展文本和intent 
065Notification notification = new Notification(notificationIcon, tickerText, 
066when); 
067Context context = getApplicationContext(); 
068Intent notificationIntent = new Intent(context, BatteryInfo.class); 
069PendingIntent contentIntent = PendingIntent.getActivity(this, 0
070notificationIntent, 0); 
071notification.setLatestEventInfo(context, contentTitle, contentText, 
072contentIntent); 
073
074// 设置本状态出现在“正在进行”而非“通知”栏目,不允许用户清除状态图标 
075notification.flags |= Notification.FLAG_ONGOING_EVENT; 
076return notification; 
077
078
079// 获得对应的电池状态图标 
080private int getStateIcon(int batteryHealth) { 
081if (batteryHealth >= 0 || batteryHealth <= 100
082return batteryStateIcons[batteryHealth]; //这里是为了方便起见而硬编码的资源数组,直接从R.java文件中提取的十六进制资源ID 
083return R.drawable.stat_sys_battery_unknown; 
084
085
086// 获得对应的充电状态图标 
087private int getChargingIcon(int batteryHealth) { 
088if (batteryHealth >= 0 && batteryHealth < 5
089return R.drawable.stat_sys_battery_charge_anim0; 
090if (batteryHealth >= 5 && batteryHealth < 10
091return R.drawable.stat_sys_battery_charge_anim01; 
092if (batteryHealth >= 10 && batteryHealth < 15
093return R.drawable.stat_sys_battery_charge_anim02; 
094if (batteryHealth >= 15 && batteryHealth < 20
095return R.drawable.stat_sys_battery_charge_anim03; 
096if (batteryHealth >= 20 && batteryHealth < 25
097return R.drawable.stat_sys_battery_charge_anim04; 
098if (batteryHealth >= 25 && batteryHealth < 30
099return R.drawable.stat_sys_battery_charge_anim05; 
100if (batteryHealth >= 30 && batteryHealth < 35
101return R.drawable.stat_sys_battery_charge_anim06; 
102if (batteryHealth >= 35 && batteryHealth < 40
103return R.drawable.stat_sys_battery_charge_anim07; 
104if (batteryHealth >= 40 && batteryHealth < 45
105return R.drawable.stat_sys_battery_charge_anim08; 
106if (batteryHealth >= 45 && batteryHealth < 50
107return R.drawable.stat_sys_battery_charge_anim09; 
108if (batteryHealth >= 50 && batteryHealth < 55
109return R.drawable.stat_sys_battery_charge_anim10; 
110if (batteryHealth >= 55 && batteryHealth < 60
111return R.drawable.stat_sys_battery_charge_anim11; 
112if (batteryHealth >= 60 && batteryHealth < 65
113return R.drawable.stat_sys_battery_charge_anim12; 
114if (batteryHealth >= 65 && batteryHealth < 70
115return R.drawable.stat_sys_battery_charge_anim13; 
116if (batteryHealth >= 70 && batteryHealth < 75
117return R.drawable.stat_sys_battery_charge_anim14; 
118if (batteryHealth >= 75 && batteryHealth < 80
119return R.drawable.stat_sys_battery_charge_anim15; 
120if (batteryHealth >= 80 && batteryHealth < 85
121return R.drawable.stat_sys_battery_charge_anim16; 
122if (batteryHealth >= 85 && batteryHealth < 90
123return R.drawable.stat_sys_battery_charge_anim17; 
124if (batteryHealth >= 90 && batteryHealth < 95
125return R.drawable.stat_sys_battery_charge_anim18; 
126if (batteryHealth >= 95 && batteryHealth < 100
127return R.drawable.stat_sys_battery_charge_anim19; 
128if (batteryHealth == 100
129return R.drawable.stat_sys_battery_charge_animfull; 
130return R.drawable.stat_sys_battery_unknown; 
131
132
133// -------------------------------私有字段-------------------------------------- 
134private NotificationManager notifyManager = null
135private Notification notification = null
136
137//这里是为了方便起见而硬编码的icon资源数组,直接从R.java文件中提取的十六进制资源ID,本数组的0号元素0x7f020002表示资源stat_sys_battery_0.png(见附件),以后累加。不同配置的ID可能不同,请读者自行修改。 
138private int batteryStateIcons[] = { 0x7f020002, 0x7f020003, 0x7f020004
1390x7f020005, 0x7f020006, 0x7f020007, 0x7f020008, 0x7f020009, 0x7f02000a
1400x7f02000b, 0x7f02000c, 0x7f02000d, 0x7f02000e, 0x7f02000f, 0x7f020010
1410x7f020011, 0x7f020012, 0x7f020013, 0x7f020014, 0x7f020015, 0x7f020016
1420x7f020017, 0x7f020018, 0x7f020019, 0x7f02001a, 0x7f02001b, 0x7f02001c
1430x7f02001d, 0x7f02001e, 0x7f02001f, 0x7f020020, 0x7f020021, 0x7f020022
1440x7f020023, 0x7f020024, 0x7f020025, 0x7f020026, 0x7f020027, 0x7f020028
1450x7f020029, 0x7f02002a, 0x7f02002b, 0x7f02002c, 0x7f02002d, 0x7f02002e
1460x7f02002f, 0x7f020030, 0x7f020031, 0x7f020032, 0x7f020033, 0x7f020034
1470x7f020035, 0x7f020036, 0x7f020037, 0x7f020038, 0x7f020039, 0x7f02003a
1480x7f02003b, 0x7f02003c, 0x7f02003d, 0x7f02003e, 0x7f02003f, 0x7f020040
1490x7f020041, 0x7f020042, 0x7f020043, 0x7f020044, 0x7f020045, 0x7f020046
1500x7f020047, 0x7f020048, 0x7f020049, 0x7f02004a, 0x7f02004b, 0x7f02004c
1510x7f02004d, 0x7f02004e, 0x7f02004f, 0x7f020050, 0x7f020051, 0x7f020052
1520x7f020053, 0x7f020054, 0x7f020055, 0x7f020056, 0x7f020057, 0x7f020058
1530x7f020059, 0x7f02005a, 0x7f02005b, 0x7f02005c, 0x7f02005d, 0x7f02005e
1540x7f02005f, 0x7f020060, 0x7f020061, 0x7f020062, 0x7f020063, 0x7f020064
1550x7f020065, 0x7f02007b }; 
156
157// 接受电池信息更新的广播 
158private BroadcastReceiver batteryChangedReceiver = new BroadcastReceiver() { 
159public void onReceive(Context context, Intent intent) { 
160int level = intent.getIntExtra("level", 0); 
161int scale = intent.getIntExtra("scale", 100); 
162int status = intent.getIntExtra("status", 0); 
163
164// 若正在充电 
165if (status == BatteryManager.BATTERY_STATUS_CHARGING) 
166notification = getNotification(getChargingIcon(level * 100 / scale), 
167"Battery Monitor", System.currentTimeMillis(), "电池电量", "正在充电"); 
168else
169notification = getNotification(getStateIcon(level * 100 / scale), 
170"Battery Monitor", System.currentTimeMillis(), "电池电量", "请及时充电"); 
171notifyManager.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服务即可  
01package com.billhoo.study; 
02
03import android.app.Activity; 
04import android.content.Intent; 
05import android.os.Bundle; 
06
07
08public class BatteryMonitor extends Activity { 
09/** Called when the activity is first created. */
10@Override
11public void onCreate(Bundle savedInstanceState) { 
12super.onCreate(savedInstanceState); 
13setContentView(R.layout.main); 
14
15//启动电池监控服务 
16startService(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" 
04android:orientation="vertical"
05android:layout_width="72dip"
06android:layout_height="72dip">
07<ImageView android:id="@+id/monitor_widget_view"
08android:layout_width="fill_parent"
09android:layout_height="fill_parent"
10
11android: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"
4android: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"
7android:resource="@xml/monitor_widget_info" />
8</receiver>
的实现代码
01package com.billhoo.study; 
02
03import android.appwidget.AppWidgetManager; 
04import android.appwidget.AppWidgetProvider; 
05import android.content.Context; 
06import android.content.Intent; 
07
08public class MonitorWidgetProvider extends AppWidgetProvider  
09
10//当Widget第一次被启动时,启动配套服务 
11@Override
12public void onEnabled(Context context) { 
13context.startService(new Intent(context,  
14
15WidgetUpdateService.class)); 
16
17
18//当Widget更新时,启动配套服务 
19@Override
20public void onUpdate(Context context, AppWidgetManager  
21
22appWidgetManager, 
23int appWidgetIds[]) { 
24super.onUpdate(context, appWidgetManager, appWidgetIds); 
25context.startService(new Intent(context,  
26
27WidgetUpdateService.class)); 
28
29
30// 当桌面上这个widget的所有实体都被删除后,停止配套服务 
31@Override
32public void onDisabled(Context context) { 
33context.stopService(new Intent(context, WidgetUpdateService.class)); 
34
35}
  编写配套的Service。 

中注册这个服务。

1<service android:name=".WidgetUpdateService" android:enabled="true" />
 

然后编写Java 代码:

001package com.billhoo.study; 
002
003import android.app.Service; 
004import android.appwidget.AppWidgetManager; 
005import android.content.BroadcastReceiver; 
006import android.content.ComponentName; 
007import android.content.Context; 
008import android.content.Intent; 
009import android.content.IntentFilter; 
010import android.os.BatteryManager; 
011import android.os.IBinder; 
012import android.widget.RemoteViews; 
013
014//用以根据电池电量更新而刷新桌面Widget的服务 
015public class WidgetUpdateService extends Service { 
016@Override
017public IBinder onBind(Intent intent) { 
018return null
019
020
021@Override
022public void onStart(Intent intent, int startId) { 
023// 向系统注册电池电量更新广播,只接受带有ACTION_BATTERRY_CHANGED事件的Intent 
024registerReceiver(this.bCR, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); 
025
026bCR = new BroadcastReceiver() { 
027@Override
028public void onReceive(Context context, Intent intent) { 
029int level = intent.getIntExtra("level", 0); 
030int scale = intent.getIntExtra("scale", 100); 
031int status = intent.getIntExtra("status", 0); 
032int batteryHealth = level * 100 / scale; 
033int icon = 0
034
035AppWidgetManager widgetManager = AppWidgetManager.getInstance(context); 
036RemoteViews widgetView = new RemoteViews(context.getPackageName(), 
037R.layout.monitor_widget_layout); 
038
039// 若正在充电 
040if (status == BatteryManager.BATTERY_STATUS_CHARGING) { 
041icon = getChargingIcon(batteryHealth); 
042widgetView.setImageViewResource(R.id.monitor_widget_view, icon 
043
044); 
045} else
046widgetView.setImageViewResource(R.id.monitor_widget_view, 
047getStateIcon(batteryHealth)); 
048widgetManager.updateAppWidget(new ComponentName(context, 
049MonitorWidgetProvider.class), widgetView); 
050
051}; 
052
053
054private BroadcastReceiver bCR = null
055
056// 获取电池状态图标 
057private int getStateIcon(int batteryHealth) { 
058if (batteryHealth >= 0 || batteryHealth <= 100
059return batteryStateIcon[batteryHealth / 5]; 
060return R.drawable.vertical_battery_unknown; 
061
062
063// 获得对应的充电状态图标 
064private int getChargingIcon(int batteryHealth) { 
065if (batteryHealth >= 0 && batteryHealth < 5
066return R.drawable.vertical_charging_00; 
067if (batteryHealth >= 5 && batteryHealth < 10
068return R.drawable.vertical_charging_01; 
069if (batteryHealth >= 10 && batteryHealth < 15
070return R.drawable.vertical_charging_02; 
071if (batteryHealth >= 15 && batteryHealth < 20
072return R.drawable.vertical_charging_03; 
073if (batteryHealth >= 20 && batteryHealth < 25
074return R.drawable.vertical_charging_04; 
075if (batteryHealth >= 25 && batteryHealth < 30
076return R.drawable.vertical_charging_05; 
077if (batteryHealth >= 30 && batteryHealth < 35
078return R.drawable.vertical_charging_06; 
079if (batteryHealth >= 35 && batteryHealth < 40
080return R.drawable.vertical_charging_07; 
081if (batteryHealth >= 40 && batteryHealth < 45
082return R.drawable.vertical_charging_08; 
083if (batteryHealth >= 45 && batteryHealth < 50
084return R.drawable.vertical_charging_09; 
085if (batteryHealth >= 50 && batteryHealth < 55
086return R.drawable.vertical_charging_10; 
087if (batteryHealth >= 55 && batteryHealth < 60
088return R.drawable.vertical_charging_11; 
089if (batteryHealth >= 60 && batteryHealth < 65
090return R.drawable.vertical_charging_12; 
091if (batteryHealth >= 65 && batteryHealth < 70
092return R.drawable.vertical_charging_13; 
093if (batteryHealth >= 70 && batteryHealth < 75
094return R.drawable.vertical_charging_14; 
095if (batteryHealth >= 75 && batteryHealth < 80
096return R.drawable.vertical_charging_15; 
097if (batteryHealth >= 80 && batteryHealth < 85
098return R.drawable.vertical_charging_16; 
099if (batteryHealth >= 85 && batteryHealth < 90
100return R.drawable.vertical_charging_17; 
101if (batteryHealth >= 90 && batteryHealth < 95
102return R.drawable.vertical_charging_18; 
103if (batteryHealth >= 95 && batteryHealth < 100
104return R.drawable.vertical_charging_19; 
105if (batteryHealth == 100
106return R.drawable.vertical_battery_full; 
107return R.drawable.stat_sys_battery_unknown; 
108
109
110private int batteryStateIcon[] = { 0x7f02007d, 0x7f02007e, 0x7f02007f
1110x7f020080, 0x7f020081, 0x7f020082, 0x7f020083, 0x7f020084, 0x7f020085
1120x7f020086, 0x7f020087, 0x7f020088, 0x7f020089, 0x7f02008a, 0x7f02008b
1130x7f02008c, 0x7f02008d, 0x7f02008e, 0x7f02008f, 0x7f020090, 0x7f020091 }; 
114}
 

自带的电池图标了,何乐不为?

原文:http://www.open-open.com/lib//view/open1327829183952.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值