Android 电池电量监控初步

整体思路概览

①由于要显示电池图标,因此需要一组对应的小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
2 <service android:name=".MonitorService" android:enabled="true" />
Bill的另一篇文章【Android开机启动Activity或Service的方法】),下面,我们将在一个Activity中启动MonitorService服务。    在AndroidManifest.xml中进行注册  
查看源码 打印 ?
1
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  
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
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

你可能感兴趣的:(Android)