Android Widget 电池插件的开发实现

来源:互联网 发布:资生堂有淘宝旗舰店吗 编辑:程序博客网 时间:2024/05/21 19:38
 最近突发奇想,想自己编一个Android电池插件放在桌面上,一是这个App确实有它的实用价值,二是编起来工程量应该不是很大,不用花太长时间,三来又能学习下Widget的开发方法,一举三得,于是,暂停下游戏开发的学习,来编一个widget先。


在查找并结合多方资料后终于实现,效果图如下:
长按桌面空白处,出现菜单,点击Widgets,此时的插件已经装入:

在电源连接时,机器人周围会星光闪闪,表明正在充电,不在充电时,周围的星光会消失。

机器人身上显示电池电量百分比。


单击机器人图标,会跳出电池信息的详情,再次单击屏幕关闭详情信息。

下面介绍代码的实现:

整个工程主要实现两个部分,一个是AppWidget部分,实现桌面Widget的显示,更新等,另一个部分就是点击widget后出现的显示电池详细信息的Activity的实现了。


首先是AppWidget部分,上代码,NewBatteryWidget.java部分:

view plaincopy to clipboardprint?
  1. <span style="font-family:Microsoft YaHei;">package com.ritterliu.newBatteryWidget;
  2. import android.app.AlarmManager;
  3. import android.app.PendingIntent;
  4. import android.app.Service;
  5. import android.appwidget.AppWidgetManager;
  6. import android.appwidget.AppWidgetProvider;
  7. import android.content.BroadcastReceiver;
  8. import android.content.ComponentName;
  9. import android.content.Context;
  10. import android.content.Intent;
  11. import android.content.IntentFilter;
  12. import android.graphics.Bitmap;
  13. import android.graphics.BitmapFactory;
  14. import android.os.IBinder;
  15. import android.widget.RemoteViews;
  16. public class NewBatteryWidgetextends AppWidgetProvider{
  17. private staticint currentBatteryLevel;
  18. private staticint currentBatteryStatus;
  19. public void onUpdate(Context context,AppWidgetManager appWidgetManager,int[] appWidgetIds)
  20. {
  21. super.onUpdate(context, appWidgetManager, appWidgetIds);
  22. /** 启动自动更新电池信息的service */
  23. context.startService(new Intent(context,updateService.class));
  24. /** 为AppWidget设置点击事件的响应,启动显示电池信息详情的activity */
  25. Intent startActivityIntent = new Intent(context,NewBatteryInfoActivity.class);
  26. PendingIntent Pintent = PendingIntent.getActivity(context,0,startActivityIntent,0);
  27. RemoteViews views = new RemoteViews(context.getPackageName(),R.layout.newrelativelayout);
  28. views.setOnClickPendingIntent(R.id.imageView,Pintent);
  29. appWidgetManager.updateAppWidget(appWidgetIds,views);
  30. }
  31. /** 自动更新电池信息的service,通过AlarmManager实现定时不间断地发送电池信息 */
  32. public staticclass updateService extends Service{
  33. Bitmap bmp; //定义机器人图片
  34. @Override
  35. public IBinder onBind(Intent intent) {
  36. // TODO Auto-generated method stub
  37. return null;
  38. }
  39. /** 定义一个接收电池信息的broascastReceiver */
  40. private BroadcastReceiver batteryReceiver=new BroadcastReceiver()
  41. {
  42. @Override
  43. public void onReceive(Context context, Intent intent) {
  44. // TODO Auto-generated method stub
  45. currentBatteryLevel=intent.getIntExtra("level",0);
  46. currentBatteryStatus=intent.getIntExtra("status",0);
  47. }
  48. };
  49. public void onStart(Intent intent,int startId)
  50. {
  51. super.onStart(intent, startId);
  52. /** 注册接收器 */
  53. registerReceiver(batteryReceiver,new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
  54. /** 定义一个AppWidgetManager */
  55. AppWidgetManager manager=AppWidgetManager.getInstance(this);
  56. /** 定义一个RemoteViews,实现对AppWidget界面控制 */
  57. RemoteViews views=new RemoteViews(getPackageName(),R.layout.newrelativelayout);
  58. if(currentBatteryStatus==2||currentBatteryStatus==5)//当正在充电或充满电时,显示充电的图片
  59. {
  60. if(currentBatteryLevel>=95)
  61. {
  62. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.jcharge);
  63. }
  64. else if(currentBatteryLevel>=85&& currentBatteryLevel<95)
  65. {
  66. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.icharge);
  67. }
  68. else if(currentBatteryLevel>=75&& currentBatteryLevel<85)
  69. {
  70. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.hcharge);
  71. }
  72. else if(currentBatteryLevel>=65&& currentBatteryLevel<75)
  73. {
  74. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.gcharge);
  75. }
  76. else if(currentBatteryLevel>=55&& currentBatteryLevel<65)
  77. {
  78. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.fcharge);
  79. }
  80. else if(currentBatteryLevel>=45&& currentBatteryLevel<55)
  81. {
  82. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.echarge);
  83. }
  84. else if(currentBatteryLevel>=35&& currentBatteryLevel<45)
  85. {
  86. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.dcharge);
  87. }
  88. else if(currentBatteryLevel>=25&& currentBatteryLevel<35)
  89. {
  90. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.ccharge);
  91. }
  92. else if(currentBatteryLevel>=15&& currentBatteryLevel<25)
  93. {
  94. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.bcharge);
  95. }
  96. else
  97. {
  98. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.acharge);
  99. }
  100. }
  101. else //未在充电时,显示不在充电状态的系列图片
  102. {
  103. if(currentBatteryLevel>=95)
  104. {
  105. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.j);
  106. }
  107. else if(currentBatteryLevel>=85&¤tBatteryLevel<95)
  108. {
  109. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.i);
  110. }
  111. else if(currentBatteryLevel>=75&¤tBatteryLevel<85)
  112. {
  113. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.h);
  114. }
  115. else if(currentBatteryLevel>=65&¤tBatteryLevel<75)
  116. {
  117. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.g);
  118. }
  119. else if(currentBatteryLevel>=55&¤tBatteryLevel<65)
  120. {
  121. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.f);
  122. }
  123. else if(currentBatteryLevel>=45&¤tBatteryLevel<55)
  124. {
  125. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.e);
  126. }
  127. else if(currentBatteryLevel>=35&¤tBatteryLevel<45)
  128. {
  129. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.d);
  130. }
  131. else if(currentBatteryLevel>=25&¤tBatteryLevel<35)
  132. {
  133. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.c);
  134. }
  135. else if(currentBatteryLevel>=15&¤tBatteryLevel<25)
  136. {
  137. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.b);
  138. }
  139. else
  140. {
  141. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.a);
  142. }
  143. }
  144. /** 设置AppWidget上显示的图片和文字的内容 */
  145. views.setImageViewBitmap(R.id.imageView,bmp);
  146. views.setTextViewText(R.id.tv,currentBatteryLevel+"%");
  147. ComponentName thisWidget=new ComponentName(this,NewBatteryWidget.class);
  148. /** 使用AlarmManager实现每隔一秒发送一次更新提示信息,实现信息实时动态变化 */
  149. long now=System.currentTimeMillis();
  150. long pause=1000;
  151. Intent alarmIntent=new Intent();
  152. alarmIntent=intent;
  153. PendingIntent pendingIntent=PendingIntent.getService(this,0, alarmIntent, 0);
  154. AlarmManager alarm=(AlarmManager)getSystemService(Context.ALARM_SERVICE);
  155. alarm.set(AlarmManager.RTC_WAKEUP,now+pause,pendingIntent);
  156. /** 更新AppWidget */
  157. manager.updateAppWidget(thisWidget, views);
  158. }
  159. }
  160. }
  161. </span>

对于Widget,配置它的显示layout,一个简单的RelativeLayout布局,一个ImageView和一个TextView,居中显示:

view plaincopy to clipboardprint?
  1. <spanstyle="font-family:Microsoft YaHei;font-size:13px;"><?xmlversion="1.0"encoding="utf-8"?>
  2. <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent">
  5. <ImageView
  6. android:id="@+id/imageView"
  7. android:layout_centerInParent="true"
  8. android:layout_width="wrap_content"
  9. android:layout_height="wrap_content"
  10. android:src="@drawable/j"
  11. />
  12. <TextView
  13. android:id="@+id/tv"
  14. android:layout_centerInParent="true"
  15. android:layout_width="wrap_content"
  16. android:layout_height="wrap_content"
  17. android:textColor="#000000"
  18. android:textStyle="bold"
  19. android:textSize="14sp"
  20. />
  21. </RelativeLayout></span>
接着就是编写配置Widget的xml了,设置Widget大小等信息,在res目录下新建一个xml文件夹用来存放Widget的配置xml文件://备注2
view plaincopy to clipboardprint?
  1. <spanstyle="font-family:Microsoft YaHei;font-size:13px;"><?xmlversion="1.0"encoding="utf-8"?>
  2. <appwidget-providerxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:minHeight="72dip"
  4. android:minWidth="72dip"
  5. android:updatePeriodMillis="1000000"
  6. android:initialLayout="@layout/newrelativelayout"
  7. >
  8. <!--
  9. 关于android:minHeight和android:minWidth
  10. 分别对应appWidget在屏幕上所占位置的高和宽,
  11. 最小高和宽各为一个单元格,值为72dip,
  12. 有资料说计算公式为(74*N)-2
  13. 例如要设置宽为四个单元格时,(74*4)-2=294
  14. android:minWidth="294dip"
  15. 注意,看网上资料说,在SDK1.5之后,
  16. android:updatePeriodMillis就没用了,
  17. 不会再定时更新appWidget了,所以这里的值
  18. 设置多少都不会有影响,但是最好设置大一点,
  19. 防止万一又有效了,更新的太频繁会不好。
  20. -->
  21. </appwidget-provider></span>

备注1,备注2:

请注意,在一些资料上说widget配置文件new_battery_widget.xml中的android:updatePeriodMillis是用来实现widget自动更新的,但本人编程时却发现,这个设置根本就没有效果,后来上网一搜,人家说这个功能在SDK1.5以后就不支持了。所以本次程序自动更新响应系统的battery change事件是通过一个AlarmManager定时发送响应来实现的,同学们千万注意,别像我一样一开始等着靠android:updatePeriodMillis实现更新,看没效果,还以为是别的什么地方出了问题,浪费了不少时间。

Widget的部分差不多了,下面介绍显示电池详情的Activity部分,上代码:

view plaincopy to clipboardprint?
  1. <span style="font-family:Microsoft YaHei;font-size:13px;">package com.ritterliu.newBatteryWidget;
  2. import android.app.Activity;
  3. import android.app.Service;
  4. import android.content.BroadcastReceiver;
  5. import android.content.Context;
  6. import android.content.Intent;
  7. import android.content.IntentFilter;
  8. import android.os.Bundle;
  9. import android.os.IBinder;
  10. import android.view.MotionEvent;
  11. import android.view.Window;
  12. import android.widget.TextView;
  13. public class NewBatteryInfoActivityextends Activity{
  14. /** 定义电池信息变量 */
  15. private staticint currentBatteryPlugged=0;
  16. private staticint currentBatteryStatus=0;
  17. private staticint currentBatteryLevel=0;
  18. private staticint currentBatteryHealth=0;
  19. private staticint currentBatteryTemperature=0;
  20. private staticint currentBatteryVoltage=0;
  21. private static String currentBatteryTechnology="";
  22. /** TextView 声明 */
  23. private static TextView tvBatteryStatus;
  24. private static TextView tvBatteryLevel;
  25. private static TextView tvBatteryHealth;
  26. private static TextView tvBatteryTemperature;
  27. private static TextView tvBatteryVoltage;
  28. private static TextView tvBatteryTechnology;
  29. /** 定义好字符串以备使用 */
  30. private static String batteryStatus="电池状态: ";
  31. private static String batteryLevel="电池电量: ";
  32. private static String batteryHealth="电池健康: ";
  33. private static String batteryTemperature="电池温度: ";
  34. private static String batteryVoltage="电池电压: ";
  35. private static String batteryTechnology="电池技术: ";
  36. private static String batteryStatusCharging="正在充电";
  37. private static String batteryStatusDischarging="正在放电";
  38. private static String batteryStatusFull="已充满";
  39. private static String batteryStatusNotCharging="未在充电";
  40. private static String batteryStatusUnknown="状态未知";
  41. private static String batteryPluggedAC="(AC)";
  42. private static String batteryPluggedUSB="(USB)";
  43. private static String batteryHealthCold="过冷";
  44. private static String batteryHealthDead="损坏";
  45. private static String batteryHealthGood="良好";
  46. private static String batteryHealthOverheat="过热";
  47. private static String batteryHealthOverVoltage="过压";
  48. private static String batteryHealthUnknown="未知";
  49. private static String batteryHealthUnspecifiedFailure="未知的故障";
  50. /** 提示Service启动标志位 */
  51. private staticboolean flag;
  52. /** 提示信息接收器 */
  53. BroadcastReceiver infoReceiver;
  54. public void onCreate(Bundle savedInstanceState)
  55. {
  56. super.onCreate(savedInstanceState);
  57. this.requestWindowFeature(Window.FEATURE_NO_TITLE);//设置activity无标题
  58. setContentView(R.layout.newlayout); //使用newlayout的布局
  59. tvBatteryStatus=(TextView)findViewById(R.id.tvBatteryStatus);
  60. tvBatteryLevel=(TextView)findViewById(R.id.tvBatteryLevel);
  61. tvBatteryHealth=(TextView)findViewById(R.id.tvBatteryHealth);
  62. tvBatteryTemperature=(TextView)findViewById(R.id.tvBatteryTemperature);
  63. tvBatteryVoltage=(TextView)findViewById(R.id.tvBatteryVoltage);
  64. tvBatteryTechnology=(TextView)findViewById(R.id.tvBatteryTechnology);
  65. flag=true; //提示service的标志位置为true
  66. infoReceiver=new BroadcastReceiver()//提示信息接收器的定义
  67. {
  68. @Override
  69. public void onReceive(Context context, Intent intent) {
  70. // TODO Auto-generated method stub
  71. setText(); //收到intent,就及时修改TextView信息,使得Activity显示时,电池信息也能动态显示
  72. }
  73. };
  74. /** 注册提示信息的intentFilter */
  75. IntentFilter filter=new IntentFilter();
  76. filter.addAction("com.ritterliu.newBatteryWidget");
  77. registerReceiver(infoReceiver,filter);
  78. /** 启动提示service */
  79. Intent startService=new Intent(this,updateService.class);
  80. startService(startService);
  81. }
  82. /** 点击屏幕任意位置,关闭电池信息Activity */
  83. public boolean onTouchEvent(MotionEvent event)
  84. {
  85. this.finish();
  86. // onDestroy();
  87. // System.exit(0);
  88. return true;
  89. }
  90. @Override
  91. protected void onDestroy() {
  92. // TODO Auto-generated method stub
  93. flag=false;
  94. unregisterReceiver(infoReceiver);
  95. super.onDestroy();
  96. }
  97. /** 及时动态修改Activity上文字信息的函数 */
  98. public staticvoid setText()
  99. {
  100. String plugState="";
  101. switch(currentBatteryPlugged)
  102. {
  103. case 0:
  104. plugState="";
  105. break;
  106. case 1:
  107. plugState=batteryPluggedAC;
  108. break;
  109. case 2:
  110. plugState=batteryPluggedUSB;
  111. break;
  112. default:
  113. plugState="";
  114. }
  115. switch(currentBatteryStatus)
  116. {
  117. case 1:
  118. tvBatteryStatus.setText(batteryStatus+batteryStatusUnknown);
  119. break;
  120. case 2:
  121. tvBatteryStatus.setText(batteryStatus+batteryStatusCharging+plugState);
  122. break;
  123. case 3:
  124. tvBatteryStatus.setText(batteryStatus+batteryStatusDischarging);
  125. break;
  126. case 4:
  127. tvBatteryStatus.setText(batteryStatus+batteryStatusNotCharging);
  128. break;
  129. case 5:
  130. tvBatteryStatus.setText(batteryStatus+batteryStatusFull+plugState);
  131. break;
  132. default:
  133. tvBatteryStatus.setText(batteryStatus+batteryStatusUnknown);
  134. }
  135. tvBatteryLevel.setText(batteryLevel+String.valueOf(currentBatteryLevel)+"%");
  136. switch(currentBatteryHealth)
  137. {
  138. case 1:
  139. tvBatteryHealth.setText(batteryHealth+batteryHealthUnknown);
  140. break;
  141. case 2:
  142. tvBatteryHealth.setText(batteryHealth+batteryHealthGood);
  143. break;
  144. case 3:
  145. tvBatteryHealth.setText(batteryHealth+batteryHealthOverheat);
  146. break;
  147. case 4:
  148. tvBatteryHealth.setText(batteryHealth+batteryHealthDead);
  149. break;
  150. case 5:
  151. tvBatteryHealth.setText(batteryHealth+batteryHealthOverVoltage);
  152. break;
  153. case 6:
  154. tvBatteryHealth.setText(batteryHealth+batteryHealthUnspecifiedFailure);
  155. break;
  156. case 7:
  157. tvBatteryHealth.setText(batteryHealth+batteryHealthCold);
  158. break;
  159. default:
  160. tvBatteryHealth.setText(batteryHealth+batteryHealthUnknown);
  161. }
  162. tvBatteryTemperature.setText(batteryTemperature+currentBatteryTemperature/10f+"℃");
  163. tvBatteryVoltage.setText(batteryVoltage+currentBatteryVoltage+"mv");
  164. tvBatteryTechnology.setText(batteryTechnology+currentBatteryTechnology);
  165. }
  166. /** 提示信息变化的service,约每隔一秒,就发送intent,
  167. * 提醒activity更新电池信息,主要为了检测电池状态的变化,
  168. * 例如连上充电时,状态会从“未在充电”变为“正在充电”
  169. * 通过调用plugged方式,还能判断是AC方式充电还是USB方式充电
  170. */
  171. public staticclass updateService extends Service{
  172. @Override
  173. public IBinder onBind(Intent intent) {
  174. // TODO Auto-generated method stub
  175. return null;
  176. }
  177. /** 定义得到电池信息的BroadcastReceiver,提取出关键信息,存入变量中 */
  178. private BroadcastReceiver batteryReceiver=new BroadcastReceiver()
  179. {
  180. @Override
  181. public void onReceive(Context context, Intent intent) {
  182. // TODO Auto-generated method stub
  183. currentBatteryStatus=intent.getIntExtra("status",0);
  184. currentBatteryLevel=intent.getIntExtra("level",0);
  185. currentBatteryHealth=intent.getIntExtra("health",0);
  186. currentBatteryTemperature=intent.getIntExtra("temperature",0);
  187. currentBatteryVoltage=intent.getIntExtra("voltage",0);
  188. currentBatteryTechnology=intent.getStringExtra("technology");
  189. currentBatteryPlugged=intent.getIntExtra("plugged",0);
  190. }
  191. };
  192. public void onStart(Intent intent,int startId)
  193. {
  194. registerReceiver(batteryReceiver,new IntentFilter(Intent.ACTION_BATTERY_CHANGED));//注册BroadcastReceiver
  195. /** 启动一个线程,约每隔一秒就发送intent提醒Activity更新电池信息 */
  196. new Thread()
  197. {
  198. public void run()
  199. {
  200. while(flag)
  201. {
  202. Intent sendInfoToActivity=new Intent();
  203. sendInfoToActivity.setAction("com.ritterliu.newBatteryWidget");
  204. sendBroadcast(sendInfoToActivity);
  205. try
  206. {
  207. Thread.sleep(1000);
  208. }
  209. catch(Exception ex)
  210. {
  211. ex.printStackTrace();
  212. }
  213. }
  214. }
  215. }.start();
  216. super.onStart(intent, startId);
  217. }
  218. }
  219. }
  220. </span>
布局文件:
view plaincopy to clipboardprint?
  1. <spanstyle="font-family:Microsoft YaHei;font-size:13px;"><?xmlversion="1.0"encoding="utf-8"?>
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent"
  5. android:orientation="vertical">
  6. <TextView
  7. android:id="@+id/tvBatteryStatus"
  8. android:layout_marginLeft="3sp"
  9. android:layout_width="wrap_content"
  10. android:layout_height="wrap_content"
  11. android:text="@string/batteryStatus"
  12. android:textSize="18dp"
  13. android:textColor="#FFFFFF"
  14. />
  15. <TextView
  16. android:id="@+id/tvBatteryLevel"
  17. android:layout_marginLeft="3sp"
  18. android:layout_width="wrap_content"
  19. android:layout_height="wrap_content"
  20. android:text="@string/batteryLevel"
  21. android:textSize="18dp"
  22. android:textColor="#FFFFFF"
  23. />
  24. <TextView
  25. android:id="@+id/tvBatteryHealth"
  26. android:layout_marginLeft="3sp"
  27. android:layout_width="wrap_content"
  28. android:layout_height="wrap_content"
  29. android:text="@string/batteryHealth"
  30. android:textSize="18dp"
  31. android:textColor="#FFFFFF"
  32. />
  33. <TextView
  34. android:id="@+id/tvBatteryTemperature"
  35. android:layout_marginLeft="3sp"
  36. android:layout_width="wrap_content"
  37. android:layout_height="wrap_content"
  38. android:text="@string/batteryTemperature"
  39. android:textSize="18dp"
  40. android:textColor="#FFFFFF"
  41. />
  42. <TextView
  43. android:id="@+id/tvBatteryVoltage"
  44. android:layout_marginLeft="3sp"
  45. android:layout_width="wrap_content"
  46. android:layout_height="wrap_content"
  47. android:text="@string/batteryVoltage"
  48. android:textSize="18dp"
  49. android:textColor="#FFFFFF"
  50. />
  51. <TextView
  52. android:id="@+id/tvBatteryTechnology"
  53. android:layout_marginLeft="3sp"
  54. android:layout_width="wrap_content"
  55. android:layout_height="wrap_content"
  56. android:text="@string/batteryTechnology"
  57. android:textSize="18dp"
  58. android:textColor="#FFFFFF"
  59. />
  60. <TextView
  61. android:id="@+id/tvInfo"
  62. android:layout_marginLeft="3sp"
  63. android:layout_width="wrap_content"
  64. android:layout_height="wrap_content"
  65. android:text="http://blog.csdn.net/ritterliu"
  66. android:textSize="15dp"
  67. android:textColor="#FFFFFF"
  68. />
  69. </LinearLayout></span>

在代码中写了注释,还有什么不清楚的部分可以留言。吐舌头

最后是AndroidManifest.xml:

view plaincopy to clipboardprint?
  1. <spanstyle="font-family:Microsoft YaHei;font-size:13px;"><?xmlversion="1.0"encoding="utf-8"?>
  2. <manifestxmlns:android="http://schemas.android.com/apk/res/android"
  3. package="com.ritterliu.newBatteryWidget"
  4. android:versionCode="1"
  5. android:versionName="1.0">
  6. <uses-sdkandroid:minSdkVersion="4"/>
  7. <application
  8. android:icon="@drawable/j"
  9. android:label="@string/app_name">
  10. <receiver
  11. android:label="@string/app_name"
  12. android:name=".NewBatteryWidget">
  13. <intent-filter>
  14. <actionandroid:name="android.appwidget.action.APPWIDGET_UPDATE"/>
  15. </intent-filter>
  16. <meta-dataandroid:name="android.appwidget.provider"
  17. android:resource="@xml/new_battery_widget"
  18. />
  19. </receiver>
  20. <serviceandroid:name=".NewBatteryWidget$updateService"/>
  21. <activityandroid:name=".NewBatteryInfoActivity"android:label="OtherActiviy_app_name"
  22. android:theme="@android:style/Theme.Dialog">
  23. <!-- android:theme="@android:style/Theme.Dialog" 这是设置Activity的主题风格为对话框形式 -->
  24. </activity>
  25. <serviceandroid:name=".NewBatteryInfoActivity$updateService"/>
  26. </application>
  27. </manifest></span>

大功告成

总结:

本次开发大概前后折腾了4天时间,这其中绕了一段弯路(就是那个android:updatePeriodMillis发火),不仅学习了如何开发Widget,还对Activity的一些写法,比如设置风格为Dialog等又有了进一步的学习,在关闭Activity时,我是直接调用的finish关闭的,也许在用法上还有不当之处,本人从9月份开始自学Android开发至今两个多月的时间,开发水平还十分有限,代码中有写的不好的地方还请大家多多指点,不甚感激。奋斗

附上完整文件下载地址,由于本人积分很少(只有19可怜),故略收1分,一周后将改为免费,谢谢大家。

http://download.csdn.net/detail/ritterliu/3791897

------------------------------------------------------------------------------------------

更新于 2011-11-21 13:15

郁闷,不能修改资源分。。。就重新发了个免费的:http://download.csdn.net/detail/lr19900105/3821420

------------------------------------------------------------------------------------------


——————————————————————————————————————————————————————

更新于2011.11.14 15:17

经过昨晚一夜的测试,发现在AppWidget中设置AlarmManager每隔一秒刷新一次频率太高,过于费电了,一夜耗电量居然占到了8%,故针对这个问题正在修改,修改完成后将及时上传。

使用AlarmManager实现每隔一秒刷新一次主要是为了实现实时的充电状态的检测,电池信息的更新自然不用这么频繁,修改中。。。

修改完成,原来的通过AlarmManager每隔一秒刷新一次实现的对充电事件的及时响应改为对ACTION_POWER_CONNECTED和ACTION_POWER_DISCONNECTED监听来实现。

就修改了AppWidget部分:

view plaincopy to clipboardprint?
  1. package com.ritterliu.newBatteryWidget;
  2. import android.app.AlarmManager;
  3. import android.app.PendingIntent;
  4. import android.app.Service;
  5. import android.appwidget.AppWidgetManager;
  6. import android.appwidget.AppWidgetProvider;
  7. import android.content.BroadcastReceiver;
  8. import android.content.ComponentName;
  9. import android.content.Context;
  10. import android.content.Intent;
  11. import android.content.IntentFilter;
  12. import android.graphics.Bitmap;
  13. import android.graphics.BitmapFactory;
  14. import android.os.IBinder;
  15. import android.util.Log;
  16. import android.widget.RemoteViews;
  17. import android.widget.Toast;
  18. public class NewBatteryWidgetextends AppWidgetProvider{
  19. private staticint currentBatteryLevel;
  20. private staticint currentBatteryStatus;
  21. private staticboolean firstTimeToCreate=true;
  22. public void onUpdate(Context context,AppWidgetManager appWidgetManager,int[] appWidgetIds)
  23. {
  24. super.onUpdate(context, appWidgetManager, appWidgetIds);
  25. /** 启动自动更新电池信息的service */
  26. context.startService(new Intent(context,updateService.class));
  27. /** 为AppWidget设置点击事件的响应,启动显示电池信息详情的activity */
  28. Intent startActivityIntent = new Intent(context,NewBatteryInfoActivity.class);
  29. PendingIntent Pintent = PendingIntent.getActivity(context,0,startActivityIntent,0);
  30. RemoteViews views = new RemoteViews(context.getPackageName(),R.layout.newrelativelayout);
  31. views.setOnClickPendingIntent(R.id.imageView,Pintent);
  32. appWidgetManager.updateAppWidget(appWidgetIds,views);
  33. }
  34. /** 自动更新电池信息的service,通过AlarmManager实现定时不间断地发送电池信息 */
  35. public staticclass updateService extends Service{
  36. Bitmap bmp; //定义机器人图片
  37. @Override
  38. public IBinder onBind(Intent intent) {
  39. // TODO Auto-generated method stub
  40. return null;
  41. }
  42. /** 定义一个接收电池信息的broascastReceiver */
  43. private BroadcastReceiver batteryReceiver=new BroadcastReceiver()
  44. {
  45. @Override
  46. public void onReceive(Context context, Intent intent) {
  47. // TODO Auto-generated method stub
  48. currentBatteryLevel=intent.getIntExtra("level",0);
  49. currentBatteryStatus=intent.getIntExtra("status",0);
  50. }
  51. };
  52. private BroadcastReceiver powerConnectedReceiver=new BroadcastReceiver()
  53. {
  54. @Override
  55. public void onReceive(Context context, Intent intent) {
  56. // TODO Auto-generated method stub
  57. setViews();
  58. }
  59. };
  60. private BroadcastReceiver powerDisconnectedReceiver=new BroadcastReceiver()
  61. {
  62. @Override
  63. public void onReceive(Context context, Intent intent) {
  64. // TODO Auto-generated method stub
  65. setViews();
  66. }
  67. };
  68. /** 设置Widget的显示 */
  69. private void setViews()
  70. {
  71. /** 定义一个AppWidgetManager */
  72. AppWidgetManager manager=AppWidgetManager.getInstance(this);
  73. /** 定义一个RemoteViews,实现对AppWidget界面控制 */
  74. RemoteViews views=new RemoteViews(getPackageName(),R.layout.newrelativelayout);
  75. if(currentBatteryStatus==2||currentBatteryStatus==5)//当正在充电或充满电时,显示充电的图片
  76. {
  77. if(currentBatteryLevel>=95)
  78. {
  79. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.jcharge);
  80. }
  81. else if(currentBatteryLevel>=85&& currentBatteryLevel<95)
  82. {
  83. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.icharge);
  84. }
  85. else if(currentBatteryLevel>=75&& currentBatteryLevel<85)
  86. {
  87. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.hcharge);
  88. }
  89. else if(currentBatteryLevel>=65&& currentBatteryLevel<75)
  90. {
  91. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.gcharge);
  92. }
  93. else if(currentBatteryLevel>=55&& currentBatteryLevel<65)
  94. {
  95. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.fcharge);
  96. }
  97. else if(currentBatteryLevel>=45&& currentBatteryLevel<55)
  98. {
  99. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.echarge);
  100. }
  101. else if(currentBatteryLevel>=35&& currentBatteryLevel<45)
  102. {
  103. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.dcharge);
  104. }
  105. else if(currentBatteryLevel>=25&& currentBatteryLevel<35)
  106. {
  107. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.ccharge);
  108. }
  109. else if(currentBatteryLevel>=15&& currentBatteryLevel<25)
  110. {
  111. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.bcharge);
  112. }
  113. else
  114. {
  115. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.acharge);
  116. }
  117. }
  118. else //未在充电时,显示不在充电状态的系列图片
  119. {
  120. if(currentBatteryLevel>=95)
  121. {
  122. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.j);
  123. }
  124. else if(currentBatteryLevel>=85&& currentBatteryLevel<95)
  125. {
  126. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.i);
  127. }
  128. else if(currentBatteryLevel>=75&& currentBatteryLevel<85)
  129. {
  130. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.h);
  131. }
  132. else if(currentBatteryLevel>=65&& currentBatteryLevel<75)
  133. {
  134. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.g);
  135. }
  136. else if(currentBatteryLevel>=55&& currentBatteryLevel<65)
  137. {
  138. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.f);
  139. }
  140. else if(currentBatteryLevel>=45&& currentBatteryLevel<55)
  141. {
  142. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.e);
  143. }
  144. else if(currentBatteryLevel>=35&& currentBatteryLevel<45)
  145. {
  146. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.d);
  147. }
  148. else if(currentBatteryLevel>=25&& currentBatteryLevel<35)
  149. {
  150. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.c);
  151. }
  152. else if(currentBatteryLevel>=15&& currentBatteryLevel<25)
  153. {
  154. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.b);
  155. }
  156. else
  157. {
  158. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.a);
  159. }
  160. }
  161. /** 设置AppWidget上显示的图片和文字的内容 */
  162. views.setImageViewBitmap(R.id.imageView,bmp);
  163. views.setTextViewText(R.id.tv,currentBatteryLevel+"%");
  164. ComponentName thisWidget=new ComponentName(this,NewBatteryWidget.class);
  165. /** 更新AppWidget */
  166. manager.updateAppWidget(thisWidget, views);
  167. }
  168. public void onStart(Intent intent,int startId)
  169. {
  170. super.onStart(intent, startId);
  171. /** 注册接收器 */
  172. registerReceiver(batteryReceiver,new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
  173. /** 增加了对于POWER_CONNECTED和DISCONNECTED事件的监听,
  174. * 以实现充电时信息的动态变化,避免了原来需要依赖AlarmManager
  175. * 每隔一秒发送检测信息来实现,节约了电量,用原来隔一秒更新的方法,
  176. * 经过一夜测试,插件耗电量居然占到了8%,汗。。。
  177. *
  178. * */
  179. registerReceiver(powerConnectedReceiver,new IntentFilter(Intent.ACTION_POWER_CONNECTED));
  180. registerReceiver(powerDisconnectedReceiver,new IntentFilter(Intent.ACTION_POWER_DISCONNECTED ));
  181. /** 使用AlarmManager实现,第一次启动Widget时隔一秒立即更新,
  182. * 以后均为两分钟发送一次更新提示信息,实现信息实时动态变化,
  183. * 实现节电功能
  184. * */
  185. long now=System.currentTimeMillis();
  186. long pause;
  187. if(firstTimeToCreate)
  188. {
  189. firstTimeToCreate=false;
  190. pause=1000;
  191. }
  192. else
  193. {
  194. pause=1000*60*2;
  195. }
  196. Intent alarmIntent=new Intent();
  197. alarmIntent=intent;
  198. PendingIntent pendingIntent=PendingIntent.getService(this,0, alarmIntent, 0);
  199. AlarmManager alarm=(AlarmManager)getSystemService(Context.ALARM_SERVICE);
  200. alarm.set(AlarmManager.RTC_WAKEUP,now+pause,pendingIntent);
  201. setViews();
  202. }
  203. }
  204. }

新的源码下载地址:

http://download.csdn.net/detail/ritterliu/3794539

同样将在一周后将改为免费,谢谢大家。吐舌头


------------------------------------------------------------------------------------------

更新于 2011-11-21 13:15

郁闷,不能修改资源分。。。就重新发了个免费的:http://download.csdn.net/detail/lr19900105/3821420

------------------------------------------------------------------------------------------



-----------------------------------------------------------------------------------------------------------------------------------------------------

更新于2011.11.15 10:52pm

真是不好意思,今天又有同学测出了BUG,桌面横竖屏切换后,点击Widget没反应了,无发启动Activity,显示电池信息详情了。

经过1个小时查找资料,修改完成,依旧是在Service中新增了一个intent检测,用来监听横竖屏切换事件,screenOrientationChangedReceiver接收到 ACTION_CONFIGURATION_CHANGED 后,再次注册widget的click事件,解决横竖屏切换后,widget点击无响应的BUG。

同样只修改了AppWidget部分,上代码:

view plaincopy to clipboardprint?
  1. package com.ritterliu.newBatteryWidgetV2;
  2. import android.app.AlarmManager;
  3. import android.app.PendingIntent;
  4. import android.app.Service;
  5. import android.appwidget.AppWidgetManager;
  6. import android.appwidget.AppWidgetProvider;
  7. import android.content.BroadcastReceiver;
  8. import android.content.ComponentName;
  9. import android.content.Context;
  10. import android.content.Intent;
  11. import android.content.IntentFilter;
  12. import android.graphics.Bitmap;
  13. import android.graphics.BitmapFactory;
  14. import android.os.IBinder;
  15. import android.widget.RemoteViews;
  16. public class NewBatteryWidgetextends AppWidgetProvider{
  17. private staticint currentBatteryLevel;
  18. private staticint currentBatteryStatus;
  19. private staticboolean firstTimeToCreate=true;
  20. /** 声明全局变量,方便screenOrientationChangedReceiver里使用 */
  21. private static AppWidgetManager appWidgetManager;
  22. private staticint[] appWidgetIds;
  23. public void onUpdate(Context context,AppWidgetManager appWidgetManager,int[] appWidgetIds)
  24. {
  25. super.onUpdate(context, appWidgetManager, appWidgetIds);
  26. /** 启动自动更新电池信息的service */
  27. context.startService(new Intent(context,updateService.class));
  28. /** 定义全局变量,方便screenOrientationChangedReceiver里使用 */
  29. this.appWidgetManager=appWidgetManager;
  30. this.appWidgetIds=appWidgetIds;
  31. /** 为AppWidget设置点击事件的响应,启动显示电池信息详情的activity */
  32. Intent startActivityIntent = new Intent(context,NewBatteryInfoActivity.class);
  33. PendingIntent Pintent = PendingIntent.getActivity(context,0,startActivityIntent,0);
  34. RemoteViews views = new RemoteViews(context.getPackageName(),R.layout.newrelativelayout);
  35. views.setOnClickPendingIntent(R.id.imageView,Pintent);
  36. appWidgetManager.updateAppWidget(appWidgetIds,views);
  37. }
  38. /** 自动更新电池信息的service,通过AlarmManager实现定时不间断地发送电池信息 */
  39. public staticclass updateService extends Service{
  40. Bitmap bmp; //定义机器人图片
  41. @Override
  42. public IBinder onBind(Intent intent) {
  43. // TODO Auto-generated method stub
  44. return null;
  45. }
  46. /** 定义一个接收电池信息的broadcastReceiver */
  47. private BroadcastReceiver batteryReceiver=new BroadcastReceiver()
  48. {
  49. @Override
  50. public void onReceive(Context context, Intent intent) {
  51. // TODO Auto-generated method stub
  52. currentBatteryLevel=intent.getIntExtra("level",0);
  53. currentBatteryStatus=intent.getIntExtra("status",0);
  54. }
  55. };
  56. /** 定义一个接受电源连接的broadcastReceiver */
  57. private BroadcastReceiver powerConnectedReceiver=new BroadcastReceiver()
  58. {
  59. @Override
  60. public void onReceive(Context context, Intent intent) {
  61. // TODO Auto-generated method stub
  62. setViews();
  63. }
  64. };
  65. /** 定义一个接受电源断开的broadcastReceiver */
  66. private BroadcastReceiver powerDisconnectedReceiver=new BroadcastReceiver()
  67. {
  68. @Override
  69. public void onReceive(Context context, Intent intent) {
  70. // TODO Auto-generated method stub
  71. setViews();
  72. }
  73. };
  74. /** 定义一个监听横竖屏切换的broadcastReceiver */
  75. private BroadcastReceiver screenOrientationChangedReceiver=new BroadcastReceiver()
  76. {
  77. public void onReceive(Context context,Intent intent)
  78. {
  79. /** 为AppWidget设置点击事件的响应,启动显示电池信息详情的activity */
  80. Intent startActivityIntent = new Intent(context,NewBatteryInfoActivity.class);
  81. PendingIntent Pintent = PendingIntent.getActivity(context,0,startActivityIntent,0);
  82. RemoteViews views = new RemoteViews(context.getPackageName(),R.layout.newrelativelayout);
  83. views.setOnClickPendingIntent(R.id.imageView,Pintent);
  84. /** 设置AppWidget上显示的图片和文字的内容 */
  85. views.setImageViewBitmap(R.id.imageView,bmp);
  86. views.setTextViewText(R.id.tv,currentBatteryLevel+"%");
  87. appWidgetManager.updateAppWidget(appWidgetIds,views);
  88. }
  89. };
  90. /** 设置Widget的显示 */
  91. private void setViews()
  92. {
  93. /** 定义一个AppWidgetManager */
  94. AppWidgetManager manager=AppWidgetManager.getInstance(this);
  95. /** 定义一个RemoteViews,实现对AppWidget界面控制 */
  96. RemoteViews views=new RemoteViews(getPackageName(),R.layout.newrelativelayout);
  97. if(currentBatteryStatus==2||currentBatteryStatus==5)//当正在充电或充满电时,显示充电的图片
  98. {
  99. if(currentBatteryLevel>=95)
  100. {
  101. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.jcharge);
  102. }
  103. else if(currentBatteryLevel>=85&& currentBatteryLevel<95)
  104. {
  105. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.icharge);
  106. }
  107. else if(currentBatteryLevel>=75&& currentBatteryLevel<85)
  108. {
  109. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.hcharge);
  110. }
  111. else if(currentBatteryLevel>=65&& currentBatteryLevel<75)
  112. {
  113. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.gcharge);
  114. }
  115. else if(currentBatteryLevel>=55&& currentBatteryLevel<65)
  116. {
  117. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.fcharge);
  118. }
  119. else if(currentBatteryLevel>=45&& currentBatteryLevel<55)
  120. {
  121. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.echarge);
  122. }
  123. else if(currentBatteryLevel>=35&& currentBatteryLevel<45)
  124. {
  125. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.dcharge);
  126. }
  127. else if(currentBatteryLevel>=25&& currentBatteryLevel<35)
  128. {
  129. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.ccharge);
  130. }
  131. else if(currentBatteryLevel>=15&& currentBatteryLevel<25)
  132. {
  133. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.bcharge);
  134. }
  135. else
  136. {
  137. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.acharge);
  138. }
  139. }
  140. else //未在充电时,显示不在充电状态的系列图片
  141. {
  142. if(currentBatteryLevel>=95)
  143. {
  144. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.j);
  145. }
  146. else if(currentBatteryLevel>=85&& currentBatteryLevel<95)
  147. {
  148. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.i);
  149. }
  150. else if(currentBatteryLevel>=75&& currentBatteryLevel<85)
  151. {
  152. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.h);
  153. }
  154. else if(currentBatteryLevel>=65&& currentBatteryLevel<75)
  155. {
  156. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.g);
  157. }
  158. else if(currentBatteryLevel>=55&& currentBatteryLevel<65)
  159. {
  160. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.f);
  161. }
  162. else if(currentBatteryLevel>=45&& currentBatteryLevel<55)
  163. {
  164. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.e);
  165. }
  166. else if(currentBatteryLevel>=35&& currentBatteryLevel<45)
  167. {
  168. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.d);
  169. }
  170. else if(currentBatteryLevel>=25&& currentBatteryLevel<35)
  171. {
  172. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.c);
  173. }
  174. else if(currentBatteryLevel>=15&& currentBatteryLevel<25)
  175. {
  176. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.b);
  177. }
  178. else
  179. {
  180. bmp=BitmapFactory.decodeResource(getResources(),R.drawable.a);
  181. }
  182. }
  183. /** 设置AppWidget上显示的图片和文字的内容 */
  184. views.setImageViewBitmap(R.id.imageView,bmp);
  185. views.setTextViewText(R.id.tv,currentBatteryLevel+"%");
  186. ComponentName thisWidget=new ComponentName(this,NewBatteryWidget.class);
  187. /** 更新AppWidget */
  188. manager.updateAppWidget(thisWidget, views);
  189. }
  190. public void onStart(Intent intent,int startId)
  191. {
  192. super.onStart(intent, startId);
  193. /** 注册接收器 */
  194. registerReceiver(batteryReceiver,new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
  195. /** 增加了对于POWER_CONNECTED和DISCONNECTED事件的监听,
  196. * 以实现充电时信息的动态变化,避免了原来需要依赖AlarmManager
  197. * 每隔一秒发送检测信息来实现,节约了电量,用原来隔一秒更新的方法,
  198. * 经过一夜测试,插件耗电量居然占到了8%,汗。。。
  199. *
  200. * */
  201. registerReceiver(powerConnectedReceiver,new IntentFilter(Intent.ACTION_POWER_CONNECTED));
  202. registerReceiver(powerDisconnectedReceiver,new IntentFilter(Intent.ACTION_POWER_DISCONNECTED ));
  203. /** 新增用以检测横竖屏切换事件 */
  204. registerReceiver(screenOrientationChangedReceiver,new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED));
  205. /** 使用AlarmManager实现,第一次启动Widget时隔一秒立即更新,
  206. * 以后均为两分钟发送一次更新提示信息,实现信息实时动态变化,
  207. * 实现节电功能
  208. * */
  209. long now=System.currentTimeMillis();
  210. long pause;
  211. if(firstTimeToCreate)
  212. {
  213. firstTimeToCreate=false;
  214. pause=1000;
  215. }
  216. else
  217. {
  218. pause=1000*60*2;
  219. }
  220. Intent alarmIntent=new Intent();
  221. alarmIntent=intent;
  222. PendingIntent pendingIntent=PendingIntent.getService(this,0, alarmIntent, 0);
  223. AlarmManager alarm=(AlarmManager)getSystemService(Context.ALARM_SERVICE);
  224. alarm.set(AlarmManager.RTC_WAKEUP,now+pause,pendingIntent);
  225. setViews();
  226. }
  227. }
  228. }

最新的工程就不上传了,大家将这个部分替换就可以了吐舌头
____________________________________________________________
原创粉丝点击