最近突发奇想,想自己编一个Android电池插件放在桌面上,一是这个App确实有它的实用价值,二是编起来工程量应该不是很大,不用花太长时间,三来又能学习下Widget的开发方法,一举三得,于是,暂停下游戏开发的学习,来编一个widget先。
在查找并结合多方资料后终于实现,效果图如下:
长按桌面空白处,出现菜单,点击Widgets,此时的插件已经装入:
在电源连接时,机器人周围会星光闪闪,表明正在充电,不在充电时,周围的星光会消失。
机器人身上显示电池电量百分比。
单击机器人图标,会跳出电池信息的详情,再次单击屏幕关闭详情信息。
对于Widget,配置它的显示layout,一个简单的RelativeLayout布局,一个ImageView和一个TextView,居中显示:
在查找并结合多方资料后终于实现,效果图如下:
长按桌面空白处,出现菜单,点击Widgets,此时的插件已经装入:
![](http://dl.iteye.com/upload/attachment/588283/08588b94-21fd-3650-b55e-87f4146b041a.png)
在电源连接时,机器人周围会星光闪闪,表明正在充电,不在充电时,周围的星光会消失。
机器人身上显示电池电量百分比。
![](http://dl.iteye.com/upload/attachment/588285/5fc42582-e944-30a5-a9e7-cdf08de0788f.png)
单击机器人图标,会跳出电池信息的详情,再次单击屏幕关闭详情信息。
![](http://dl.iteye.com/upload/attachment/588287/6ab876ff-6745-3d1d-a90e-8d493a89affb.png)
下面介绍代码的实现:
整个工程主要实现两个部分,一个是AppWidget部分,实现桌面Widget的显示,更新等,另一个部分就是点击widget后出现的显示电池详细信息的Activity的实现了。
首先是AppWidget部分,上代码,NewBatteryWidget.java部分:
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.IBinder;
import android.widget.RemoteViews;
public class NewBatteryWidget extends AppWidgetProvider{
private static int currentBatteryLevel;
private static int currentBatteryStatus;
public void onUpdate(Context context,AppWidgetManager appWidgetManager,int[] appWidgetIds)
{
super.onUpdate(context, appWidgetManager, appWidgetIds);
/** 启动自动更新电池信息的service */
context.startService(new Intent(context,updateService.class));
/** 为AppWidget设置点击事件的响应,启动显示电池信息详情的activity */
Intent startActivityIntent = new Intent(context,NewBatteryInfoActivity.class);
PendingIntent Pintent = PendingIntent.getActivity(context,0,startActivityIntent,0);
RemoteViews views = new RemoteViews(context.getPackageName(),R.layout.newrelativelayout);
views.setOnClickPendingIntent(R.id.imageView,Pintent);
appWidgetManager.updateAppWidget(appWidgetIds,views);
}
/** 自动更新电池信息的service,通过AlarmManager实现定时不间断地发送电池信息 */
public static class updateService extends Service{
Bitmap bmp; //定义机器人图片
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
/** 定义一个接收电池信息的broascastReceiver */
private BroadcastReceiver batteryReceiver=new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
currentBatteryLevel=intent.getIntExtra("level", 0);
currentBatteryStatus=intent.getIntExtra("status", 0);
}
};
public void onStart(Intent intent,int startId)
{
super.onStart(intent, startId);
/** 注册接收器 */
registerReceiver(batteryReceiver,new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
/** 定义一个AppWidgetManager */
AppWidgetManager manager=AppWidgetManager.getInstance(this);
/** 定义一个RemoteViews,实现对AppWidget界面控制 */
RemoteViews views=new RemoteViews(getPackageName(),R.layout.newrelativelayout);
if(currentBatteryStatus==2||currentBatteryStatus==5) //当正在充电或充满电时,显示充电的图片
{
if(currentBatteryLevel>=95)
{
bmp=BitmapFactory.decodeResource(getResources(),R.drawable.jcharge);
}
else if(currentBatteryLevel>=85&& currentBatteryLevel<95)
{
bmp=BitmapFactory.decodeResource(getResources(),R.drawable.icharge);
}
else if(currentBatteryLevel>=75&& currentBatteryLevel<85)
{
bmp=BitmapFactory.decodeResource(getResources(),R.drawable.hcharge);
}
else if(currentBatteryLevel>=65&& currentBatteryLevel<75)
{
bmp=BitmapFactory.decodeResource(getResources(),R.drawable.gcharge);
}
else if(currentBatteryLevel>=55&& currentBatteryLevel<65)
{
bmp=BitmapFactory.decodeResource(getResources(),R.drawable.fcharge);
}
else if(currentBatteryLevel>=45&& currentBatteryLevel<55)
{
bmp=BitmapFactory.decodeResource(getResources(),R.drawable.echarge);
}
else if(currentBatteryLevel>=35&& currentBatteryLevel<45)
{
bmp=BitmapFactory.decodeResource(getResources(),R.drawable.dcharge);
}
else if(currentBatteryLevel>=25&& currentBatteryLevel<35)
{
bmp=BitmapFactory.decodeResource(getResources(),R.drawable.ccharge);
}
else if(currentBatteryLevel>=15&& currentBatteryLevel<25)
{
bmp=BitmapFactory.decodeResource(getResources(),R.drawable.bcharge);
}
else
{
bmp=BitmapFactory.decodeResource(getResources(),R.drawable.acharge);
}
}
else //未在充电时,显示不在充电状态的系列图片
{
if(currentBatteryLevel>=95)
{
bmp=BitmapFactory.decodeResource(getResources(),R.drawable.j);
}
else if(currentBatteryLevel>=85&¤tBatteryLevel<95)
{
bmp=BitmapFactory.decodeResource(getResources(),R.drawable.i);
}
else if(currentBatteryLevel>=75&¤tBatteryLevel<85)
{
bmp=BitmapFactory.decodeResource(getResources(),R.drawable.h);
}
else if(currentBatteryLevel>=65&¤tBatteryLevel<75)
{
bmp=BitmapFactory.decodeResource(getResources(),R.drawable.g);
}
else if(currentBatteryLevel>=55&¤tBatteryLevel<65)
{
bmp=BitmapFactory.decodeResource(getResources(),R.drawable.f);
}
else if(currentBatteryLevel>=45&¤tBatteryLevel<55)
{
bmp=BitmapFactory.decodeResource(getResources(),R.drawable.e);
}
else if(currentBatteryLevel>=35&¤tBatteryLevel<45)
{
bmp=BitmapFactory.decodeResource(getResources(),R.drawable.d);
}
else if(currentBatteryLevel>=25&¤tBatteryLevel<35)
{
bmp=BitmapFactory.decodeResource(getResources(),R.drawable.c);
}
else if(currentBatteryLevel>=15&¤tBatteryLevel<25)
{
bmp=BitmapFactory.decodeResource(getResources(),R.drawable.b);
}
else
{
bmp=BitmapFactory.decodeResource(getResources(),R.drawable.a);
}
}
/** 设置AppWidget上显示的图片和文字的内容 */
views.setImageViewBitmap(R.id.imageView,bmp);
views.setTextViewText(R.id.tv,currentBatteryLevel+"%");
ComponentName thisWidget=new ComponentName(this,NewBatteryWidget.class);
/** 使用AlarmManager实现每隔一秒发送一次更新提示信息,实现信息实时动态变化 */
long now=System.currentTimeMillis();
long pause=1000;
Intent alarmIntent=new Intent();
alarmIntent=intent;
PendingIntent pendingIntent=PendingIntent.getService(this, 0, alarmIntent, 0);
AlarmManager alarm=(AlarmManager)getSystemService(Context.ALARM_SERVICE);
alarm.set(AlarmManager.RTC_WAKEUP,now+pause,pendingIntent);
/** 更新AppWidget */
manager.updateAppWidget(thisWidget, views);
}
}
}
对于Widget,配置它的显示layout,一个简单的RelativeLayout布局,一个ImageView和一个TextView,居中显示:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ImageView
android:id="@+id/imageView"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/j"
/>
<TextView
android:id="@+id/tv"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
android:textStyle="bold"
android:textSize="14sp"
/>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" > <ImageView android:id="@+id/imageView" android:layout_centerInParent="true" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/j" /> <TextView android:id="@+id/tv" android:layout_centerInParent="true" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#000000" android:textStyle="bold" android:textSize="14sp" />
</RelativeLayout>
接着就是编写配置Widget的xml了,设置Widget大小等信息,在res目录下新建一个xml文件夹用来存放Widget的配置xml文件:
<?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minHeight="72dip" android:minWidth="72dip" android:updatePeriodMillis="1000000" android:initialLayout="@layout/newrelativelayout" > <!-- 关于android:minHeight和android:minWidth 分别对应appWidget在屏幕上所占位置的高和宽, 最小高和宽各为一个单元格,值为72dip, 有资料说计算公式为(74*N)-2 例如要设置宽为四个单元格时,(74*4)-2=294 android:minWidth="294dip" 注意,看网上资料说,在SDK1.5之后, android:updatePeriodMillis就没用了, 不会再定时更新appWidget了,所以这里的值 设置多少都不会有影响,但是最好设置大一点, 防止万一又有效了,更新的太频繁会不好。 --> </appwidget-provider></span> <span style="font-family:Microsoft YaHei;font-size:13px;"><?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minHeight="72dip" android:minWidth="72dip" android:updatePeriodMillis="1000000" android:initialLayout="@layout/newrelativelayout" > <!-- 关于android:minHeight和android:minWidth 分别对应appWidget在屏幕上所占位置的高和宽, 最小高和宽各为一个单元格,值为72dip, 有资料说计算公式为(74*N)-2 例如要设置宽为四个单元格时,(74*4)-2=294 android:minWidth="294dip" 注意,看网上资料说,在SDK1.5之后, android:updatePeriodMillis就没用了, 不会再定时更新appWidget了,所以这里的值 设置多少都不会有影响,但是最好设置大一点, 防止万一又有效了,更新的太频繁会不好。 --> </appwidget-provider>
备注1,备注2:
请注意,在一些资料上说widget配置文件new_battery_widget.xml中的android:updatePeriodMillis是用来实现widget自动更新的,但本人编程时却发现,这个设置根本就没有效果,后来上网一搜,人家说这个功能在SDK1.5以后就不支持了。所以本次程序自动更新响应系统的battery change事件是通过一个AlarmManager定时发送响应来实现的,同学们千万注意,别像我一样一开始等着靠android:updatePeriodMillis实现更新,看没效果,还以为是别的什么地方出了问题,浪费了不少时间。
Widget的部分差不多了,下面介绍显示电池详情的Activity部分,上代码:
import android.app.Activity; import android.app.Service; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.os.IBinder; import android.view.MotionEvent; import android.view.Window; import android.widget.TextView; public class NewBatteryInfoActivity extends Activity{ /** 定义电池信息变量 */ private static int currentBatteryPlugged=0; private static int currentBatteryStatus=0; private static int currentBatteryLevel=0; private static int currentBatteryHealth=0; private static int currentBatteryTemperature=0; private static int currentBatteryVoltage=0; private static String currentBatteryTechnology=""; /** TextView 声明 */ private static TextView tvBatteryStatus; private static TextView tvBatteryLevel; private static TextView tvBatteryHealth; private static TextView tvBatteryTemperature; private static TextView tvBatteryVoltage; private static TextView tvBatteryTechnology; /** 定义好字符串以备使用 */ private static String batteryStatus="电池状态: "; private static String batteryLevel="电池电量: "; private static String batteryHealth="电池健康: "; private static String batteryTemperature="电池温度: "; private static String batteryVoltage="电池电压: "; private static String batteryTechnology="电池技术: "; private static String batteryStatusCharging="正在充电"; private static String batteryStatusDischarging="正在放电"; private static String batteryStatusFull="已充满"; private static String batteryStatusNotCharging="未在充电"; private static String batteryStatusUnknown="状态未知"; private static String batteryPluggedAC="(AC)"; private static String batteryPluggedUSB="(USB)"; private static String batteryHealthCold="过冷"; private static String batteryHealthDead="损坏"; private static String batteryHealthGood="良好"; private static String batteryHealthOverheat="过热"; private static String batteryHealthOverVoltage="过压"; private static String batteryHealthUnknown="未知"; private static String batteryHealthUnspecifiedFailure="未知的故障"; /** 提示Service启动标志位 */ private static boolean flag; /** 提示信息接收器 */ BroadcastReceiver infoReceiver; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.requestWindowFeature(Window.FEATURE_NO_TITLE); //设置activity无标题 setContentView(R.layout.newlayout); //使用newlayout的布局 tvBatteryStatus=(TextView)findViewById(R.id.tvBatteryStatus); tvBatteryLevel=(TextView)findViewById(R.id.tvBatteryLevel); tvBatteryHealth=(TextView)findViewById(R.id.tvBatteryHealth); tvBatteryTemperature=(TextView)findViewById(R.id.tvBatteryTemperature); tvBatteryVoltage=(TextView)findViewById(R.id.tvBatteryVoltage); tvBatteryTechnology=(TextView)findViewById(R.id.tvBatteryTechnology); flag=true; //提示service的标志位置为true infoReceiver=new BroadcastReceiver() //提示信息接收器的定义 { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub setText(); //收到intent,就及时修改TextView信息,使得Activity显示时,电池信息也能动态显示 } }; /** 注册提示信息的intentFilter */ IntentFilter filter=new IntentFilter(); filter.addAction("com.ritterliu.newBatteryWidget"); registerReceiver(infoReceiver,filter); /** 启动提示service */ Intent startService=new Intent(this,updateService.class); startService(startService); } /** 点击屏幕任意位置,关闭电池信息Activity */ public boolean onTouchEvent(MotionEvent event) { this.finish(); // onDestroy(); // System.exit(0); return true; } @Override protected void onDestroy() { // TODO Auto-generated method stub flag=false; unregisterReceiver(infoReceiver); super.onDestroy(); } /** 及时动态修改Activity上文字信息的函数 */ public static void setText() { String plugState=""; switch(currentBatteryPlugged) { case 0: plugState=""; break; case 1: plugState=batteryPluggedAC; break; case 2: plugState=batteryPluggedUSB; break; default: plugState=""; } switch(currentBatteryStatus) { case 1: tvBatteryStatus.setText(batteryStatus+batteryStatusUnknown); break; case 2: tvBatteryStatus.setText(batteryStatus+batteryStatusCharging+plugState); break; case 3: tvBatteryStatus.setText(batteryStatus+batteryStatusDischarging); break; case 4: tvBatteryStatus.setText(batteryStatus+batteryStatusNotCharging); break; case 5: tvBatteryStatus.setText(batteryStatus+batteryStatusFull+plugState); break; default: tvBatteryStatus.setText(batteryStatus+batteryStatusUnknown); } tvBatteryLevel.setText(batteryLevel+String.valueOf(currentBatteryLevel)+"%"); switch(currentBatteryHealth) { case 1: tvBatteryHealth.setText(batteryHealth+batteryHealthUnknown); break; case 2: tvBatteryHealth.setText(batteryHealth+batteryHealthGood); break; case 3: tvBatteryHealth.setText(batteryHealth+batteryHealthOverheat); break; case 4: tvBatteryHealth.setText(batteryHealth+batteryHealthDead); break; case 5: tvBatteryHealth.setText(batteryHealth+batteryHealthOverVoltage); break; case 6: tvBatteryHealth.setText(batteryHealth+batteryHealthUnspecifiedFailure); break; case 7: tvBatteryHealth.setText(batteryHealth+batteryHealthCold); break; default: tvBatteryHealth.setText(batteryHealth+batteryHealthUnknown); } tvBatteryTemperature.setText(batteryTemperature+currentBatteryTemperature/10f+"℃"); tvBatteryVoltage.setText(batteryVoltage+currentBatteryVoltage+"mv"); tvBatteryTechnology.setText(batteryTechnology+currentBatteryTechnology); } /** 提示信息变化的service,约每隔一秒,就发送intent, * 提醒activity更新电池信息,主要为了检测电池状态的变化, * 例如连上充电时,状态会从“未在充电”变为“正在充电” * 通过调用plugged方式,还能判断是AC方式充电还是USB方式充电 */ public static class updateService extends Service{ @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return null; } /** 定义得到电池信息的BroadcastReceiver,提取出关键信息,存入变量中 */ private BroadcastReceiver batteryReceiver=new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub currentBatteryStatus=intent.getIntExtra("status", 0); currentBatteryLevel=intent.getIntExtra("level", 0); currentBatteryHealth=intent.getIntExtra("health", 0); currentBatteryTemperature=intent.getIntExtra("temperature",0); currentBatteryVoltage=intent.getIntExtra("voltage",0); currentBatteryTechnology=intent.getStringExtra("technology"); currentBatteryPlugged=intent.getIntExtra("plugged",0); } }; public void onStart(Intent intent,int startId) { registerReceiver(batteryReceiver,new IntentFilter(Intent.ACTION_BATTERY_CHANGED));//注册BroadcastReceiver /** 启动一个线程,约每隔一秒就发送intent提醒Activity更新电池信息 */ new Thread() { public void run() { while(flag) { Intent sendInfoToActivity=new Intent(); sendInfoToActivity.setAction("com.ritterliu.newBatteryWidget"); sendBroadcast(sendInfoToActivity); try { Thread.sleep(1000); } catch(Exception ex) { ex.printStackTrace(); } } } }.start(); super.onStart(intent, startId); } } }
import android.app.Activity; import android.app.Service; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.os.IBinder; import android.view.MotionEvent; import android.view.Window; import android.widget.TextView; public class NewBatteryInfoActivity extends Activity{ /** 定义电池信息变量 */ private static int currentBatteryPlugged=0; private static int currentBatteryStatus=0; private static int currentBatteryLevel=0; private static int currentBatteryHealth=0; private static int currentBatteryTemperature=0; private static int currentBatteryVoltage=0; private static String currentBatteryTechnology=""; /** TextView 声明 */ private static TextView tvBatteryStatus; private static TextView tvBatteryLevel; private static TextView tvBatteryHealth; private static TextView tvBatteryTemperature; private static TextView tvBatteryVoltage; private static TextView tvBatteryTechnology; /** 定义好字符串以备使用 */ private static String batteryStatus="电池状态: "; private static String batteryLevel="电池电量: "; private static String batteryHealth="电池健康: "; private static String batteryTemperature="电池温度: "; private static String batteryVoltage="电池电压: "; private static String batteryTechnology="电池技术: "; private static String batteryStatusCharging="正在充电"; private static String batteryStatusDischarging="正在放电"; private static String batteryStatusFull="已充满"; private static String batteryStatusNotCharging="未在充电"; private static String batteryStatusUnknown="状态未知"; private static String batteryPluggedAC="(AC)"; private static String batteryPluggedUSB="(USB)"; private static String batteryHealthCold="过冷"; private static String batteryHealthDead="损坏"; private static String batteryHealthGood="良好"; private static String batteryHealthOverheat="过热"; private static String batteryHealthOverVoltage="过压"; private static String batteryHealthUnknown="未知"; private static String batteryHealthUnspecifiedFailure="未知的故障"; /** 提示Service启动标志位 */ private static boolean flag; /** 提示信息接收器 */ BroadcastReceiver infoReceiver; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.requestWindowFeature(Window.FEATURE_NO_TITLE); //设置activity无标题 setContentView(R.layout.newlayout); //使用newlayout的布局 tvBatteryStatus=(TextView)findViewById(R.id.tvBatteryStatus); tvBatteryLevel=(TextView)findViewById(R.id.tvBatteryLevel); tvBatteryHealth=(TextView)findViewById(R.id.tvBatteryHealth); tvBatteryTemperature=(TextView)findViewById(R.id.tvBatteryTemperature); tvBatteryVoltage=(TextView)findViewById(R.id.tvBatteryVoltage); tvBatteryTechnology=(TextView)findViewById(R.id.tvBatteryTechnology); flag=true; //提示service的标志位置为true infoReceiver=new BroadcastReceiver() //提示信息接收器的定义 { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub setText(); //收到intent,就及时修改TextView信息,使得Activity显示时,电池信息也能动态显示 } }; /** 注册提示信息的intentFilter */ IntentFilter filter=new IntentFilter(); filter.addAction("com.ritterliu.newBatteryWidget"); registerReceiver(infoReceiver,filter); /** 启动提示service */ Intent startService=new Intent(this,updateService.class); startService(startService); } /** 点击屏幕任意位置,关闭电池信息Activity */ public boolean onTouchEvent(MotionEvent event) { this.finish(); // onDestroy(); // System.exit(0); return true; } @Override protected void onDestroy() { // TODO Auto-generated method stub flag=false; unregisterReceiver(infoReceiver); super.onDestroy(); } /** 及时动态修改Activity上文字信息的函数 */ public static void setText() { String plugState=""; switch(currentBatteryPlugged) { case 0: plugState=""; break; case 1: plugState=batteryPluggedAC; break; case 2: plugState=batteryPluggedUSB; break; default: plugState=""; } switch(currentBatteryStatus) { case 1: tvBatteryStatus.setText(batteryStatus+batteryStatusUnknown); break; case 2: tvBatteryStatus.setText(batteryStatus+batteryStatusCharging+plugState); break; case 3: tvBatteryStatus.setText(batteryStatus+batteryStatusDischarging); break; case 4: tvBatteryStatus.setText(batteryStatus+batteryStatusNotCharging); break; case 5: tvBatteryStatus.setText(batteryStatus+batteryStatusFull+plugState); break; default: tvBatteryStatus.setText(batteryStatus+batteryStatusUnknown); } tvBatteryLevel.setText(batteryLevel+String.valueOf(currentBatteryLevel)+"%"); switch(currentBatteryHealth) { case 1: tvBatteryHealth.setText(batteryHealth+batteryHealthUnknown); break; case 2: tvBatteryHealth.setText(batteryHealth+batteryHealthGood); break; case 3: tvBatteryHealth.setText(batteryHealth+batteryHealthOverheat); break; case 4: tvBatteryHealth.setText(batteryHealth+batteryHealthDead); break; case 5: tvBatteryHealth.setText(batteryHealth+batteryHealthOverVoltage); break; case 6: tvBatteryHealth.setText(batteryHealth+batteryHealthUnspecifiedFailure); break; case 7: tvBatteryHealth.setText(batteryHealth+batteryHealthCold); break; default: tvBatteryHealth.setText(batteryHealth+batteryHealthUnknown); } tvBatteryTemperature.setText(batteryTemperature+currentBatteryTemperature/10f+"℃"); tvBatteryVoltage.setText(batteryVoltage+currentBatteryVoltage+"mv"); tvBatteryTechnology.setText(batteryTechnology+currentBatteryTechnology); }
/** 提示信息变化的service,约每隔一秒,就发送intent, * 提醒activity更新电池信息,主要为了检测电池状态的变化, * 例如连上充电时,状态会从“未在充电”变为“正在充电” * 通过调用plugged方式,还能判断是AC方式充电还是USB方式充电 */ public static class updateService extends Service{ @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return null; } /** 定义得到电池信息的BroadcastReceiver,提取出关键信息,存入变量中 */ private BroadcastReceiver batteryReceiver=new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub currentBatteryStatus=intent.getIntExtra("status", 0); currentBatteryLevel=intent.getIntExtra("level", 0); currentBatteryHealth=intent.getIntExtra("health", 0); currentBatteryTemperature=intent.getIntExtra("temperature",0); currentBatteryVoltage=intent.getIntExtra("voltage",0); currentBatteryTechnology=intent.getStringExtra("technology"); currentBatteryPlugged=intent.getIntExtra("plugged",0); } }; public void onStart(Intent intent,int startId) { registerReceiver(batteryReceiver,new IntentFilter(Intent.ACTION_BATTERY_CHANGED));//注册BroadcastReceiver /** 启动一个线程,约每隔一秒就发送intent提醒Activity更新电池信息 */ new Thread() { public void run() { while(flag) { Intent sendInfoToActivity=new Intent(); sendInfoToActivity.setAction("com.ritterliu.newBatteryWidget"); sendBroadcast(sendInfoToActivity); try { Thread.sleep(1000); } catch(Exception ex) { ex.printStackTrace(); } } } }.start(); super.onStart(intent, startId); } } }
布局文件:<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:id="@+id/tvBatteryStatus" android:layout_marginLeft="3sp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/batteryStatus" android:textSize="18dp" android:textColor="#FFFFFF" /> <TextView android:id="@+id/tvBatteryLevel" android:layout_marginLeft="3sp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/batteryLevel" android:textSize="18dp" android:textColor="#FFFFFF" /> <TextView android:id="@+id/tvBatteryHealth" android:layout_marginLeft="3sp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/batteryHealth" android:textSize="18dp" android:textColor="#FFFFFF" /> <TextView android:id="@+id/tvBatteryTemperature" android:layout_marginLeft="3sp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/batteryTemperature" android:textSize="18dp" android:textColor="#FFFFFF" /> <TextView android:id="@+id/tvBatteryVoltage" android:layout_marginLeft="3sp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/batteryVoltage" android:textSize="18dp" android:textColor="#FFFFFF" /> <TextView android:id="@+id/tvBatteryTechnology" android:layout_marginLeft="3sp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/batteryTechnology" android:textSize="18dp" android:textColor="#FFFFFF" /> <TextView android:id="@+id/tvInfo" android:layout_marginLeft="3sp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="http://blog.csdn.net/ritterliu" android:textSize="15dp" android:textColor="#FFFFFF" /> </LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:id="@+id/tvBatteryStatus" android:layout_marginLeft="3sp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/batteryStatus" android:textSize="18dp" android:textColor="#FFFFFF" /> <TextView android:id="@+id/tvBatteryLevel" android:layout_marginLeft="3sp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/batteryLevel" android:textSize="18dp" android:textColor="#FFFFFF" /> <TextView android:id="@+id/tvBatteryHealth" android:layout_marginLeft="3sp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/batteryHealth" android:textSize="18dp" android:textColor="#FFFFFF" /> <TextView android:id="@+id/tvBatteryTemperature" android:layout_marginLeft="3sp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/batteryTemperature" android:textSize="18dp" android:textColor="#FFFFFF" /> <TextView android:id="@+id/tvBatteryVoltage" android:layout_marginLeft="3sp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/batteryVoltage" android:textSize="18dp" android:textColor="#FFFFFF" /> <TextView android:id="@+id/tvBatteryTechnology" android:layout_marginLeft="3sp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/batteryTechnology" android:textSize="18dp" android:textColor="#FFFFFF" /> <TextView android:id="@+id/tvInfo" android:layout_marginLeft="3sp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="http://blog.csdn.net/ritterliu" android:textSize="15dp" android:textColor="#FFFFFF" /> </LinearLayout>
在代码中写了注释,还有什么不清楚的部分可以留言。
最后是AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.ritterliu.newBatteryWidget" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="4" /> <application android:icon="@drawable/j" android:label="@string/app_name" > <receiver android:label="@string/app_name" android:name=".NewBatteryWidget" > <intent-filter > <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/new_battery_widget" /> </receiver> <service android:name=".NewBatteryWidget$updateService"/> <activity android:name=".NewBatteryInfoActivity" android:label="OtherActiviy_app_name" android:theme="@android:style/Theme.Dialog"> <!-- android:theme="@android:style/Theme.Dialog" 这是设置Activity的主题风格为对话框形式 --> </activity> <service android:name=".NewBatteryInfoActivity$updateService"/> </application> </manifest>
总结:
本次开发大概前后折腾了4天时间,这其中绕了一段弯路(就是那个android:updatePeriodMillis),不仅学习了如何开发Widget,还对Activity的一些写法,比如设置风格为Dialog等又有了进一步的学习,在关闭Activity时,我是直接调用的finish关闭的,也许在用法上还有不当之处,本人从9月份开始自学Android开发至今两个多月的时间,开发水平还十分有限,代码中有写的不好的地方还请大家多多指点,不甚感激。
附上完整文件下载地址,由于本人积分很少(只有19 ),故略收1分,一周后将改为免费,谢谢大家。
http://download.csdn.net/detail/ritterliu/3791897
更新于2011.11.14 15:17
经过昨晚一夜的测试,发现在AppWidget中设置AlarmManager每隔一秒刷新一次频率太高,过于费电了,一夜耗电量居然占到了8%,故针对这个问题正在修改,修改完成后将及时上传。
使用AlarmManager实现每隔一秒刷新一次主要是为了实现实时的充电状态的检测,电池信息的更新自然不用这么频繁,修改中。。。
修改完成,原来的通过AlarmManager每隔一秒刷新一次实现的对充电事件的及时响应改为对ACTION_POWER_CONNECTED和ACTION_POWER_DISCONNECTED监听来实现。
就修改了AppWidget部分:
import android.app.AlarmManager; import android.app.PendingIntent; import android.app.Service; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.IBinder; import android.util.Log; import android.widget.RemoteViews; import android.widget.Toast; public class NewBatteryWidget extends AppWidgetProvider{ private static int currentBatteryLevel; private static int currentBatteryStatus; private static boolean firstTimeToCreate=true; public void onUpdate(Context context,AppWidgetManager appWidgetManager,int[] appWidgetIds) { super.onUpdate(context, appWidgetManager, appWidgetIds); /** 启动自动更新电池信息的service */ context.startService(new Intent(context,updateService.class)); /** 为AppWidget设置点击事件的响应,启动显示电池信息详情的activity */ Intent startActivityIntent = new Intent(context,NewBatteryInfoActivity.class); PendingIntent Pintent = PendingIntent.getActivity(context,0,startActivityIntent,0); RemoteViews views = new RemoteViews(context.getPackageName(),R.layout.newrelativelayout); views.setOnClickPendingIntent(R.id.imageView,Pintent); appWidgetManager.updateAppWidget(appWidgetIds,views); } /** 自动更新电池信息的service,通过AlarmManager实现定时不间断地发送电池信息 */ public static class updateService extends Service{ Bitmap bmp; //定义机器人图片 @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return null; } /** 定义一个接收电池信息的broascastReceiver */ private BroadcastReceiver batteryReceiver=new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub currentBatteryLevel=intent.getIntExtra("level", 0); currentBatteryStatus=intent.getIntExtra("status", 0); } }; private BroadcastReceiver powerConnectedReceiver=new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub setViews(); } }; private BroadcastReceiver powerDisconnectedReceiver=new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub setViews(); } }; /** 设置Widget的显示 */ private void setViews() { /** 定义一个AppWidgetManager */ AppWidgetManager manager=AppWidgetManager.getInstance(this); /** 定义一个RemoteViews,实现对AppWidget界面控制 */ RemoteViews views=new RemoteViews(getPackageName(),R.layout.newrelativelayout); if(currentBatteryStatus==2||currentBatteryStatus==5) //当正在充电或充满电时,显示充电的图片 { if(currentBatteryLevel>=95) { bmp=BitmapFactory.decodeResource(getResources(),R.drawable.jcharge); } else if(currentBatteryLevel>=85&& currentBatteryLevel<95) { bmp=BitmapFactory.decodeResource(getResources(),R.drawable.icharge); } else if(currentBatteryLevel>=75&& currentBatteryLevel<85) { bmp=BitmapFactory.decodeResource(getResources(),R.drawable.hcharge); } else if(currentBatteryLevel>=65&& currentBatteryLevel<75) { bmp=BitmapFactory.decodeResource(getResources(),R.drawable.gcharge); } else if(currentBatteryLevel>=55&& currentBatteryLevel<65) { bmp=BitmapFactory.decodeResource(getResources(),R.drawable.fcharge); } else if(currentBatteryLevel>=45&& currentBatteryLevel<55) { bmp=BitmapFactory.decodeResource(getResources(),R.drawable.echarge); } else if(currentBatteryLevel>=35&& currentBatteryLevel<45) { bmp=BitmapFactory.decodeResource(getResources(),R.drawable.dcharge); } else if(currentBatteryLevel>=25&& currentBatteryLevel<35) { bmp=BitmapFactory.decodeResource(getResources(),R.drawable.ccharge); } else if(currentBatteryLevel>=15&& currentBatteryLevel<25) { bmp=BitmapFactory.decodeResource(getResources(),R.drawable.bcharge); } else { bmp=BitmapFactory.decodeResource(getResources(),R.drawable.acharge); } } else //未在充电时,显示不在充电状态的系列图片 { if(currentBatteryLevel>=95) { bmp=BitmapFactory.decodeResource(getResources(),R.drawable.j); } else if(currentBatteryLevel>=85&& currentBatteryLevel<95) { bmp=BitmapFactory.decodeResource(getResources(),R.drawable.i); } else if(currentBatteryLevel>=75&& currentBatteryLevel<85) { bmp=BitmapFactory.decodeResource(getResources(),R.drawable.h); } else if(currentBatteryLevel>=65&& currentBatteryLevel<75) { bmp=BitmapFactory.decodeResource(getResources(),R.drawable.g); } else if(currentBatteryLevel>=55&& currentBatteryLevel<65) { bmp=BitmapFactory.decodeResource(getResources(),R.drawable.f); } else if(currentBatteryLevel>=45&& currentBatteryLevel<55) { bmp=BitmapFactory.decodeResource(getResources(),R.drawable.e); } else if(currentBatteryLevel>=35&& currentBatteryLevel<45) { bmp=BitmapFactory.decodeResource(getResources(),R.drawable.d); } else if(currentBatteryLevel>=25&& currentBatteryLevel<35) { bmp=BitmapFactory.decodeResource(getResources(),R.drawable.c); } else if(currentBatteryLevel>=15&& currentBatteryLevel<25) { bmp=BitmapFactory.decodeResource(getResources(),R.drawable.b); } else { bmp=BitmapFactory.decodeResource(getResources(),R.drawable.a); } } /** 设置AppWidget上显示的图片和文字的内容 */ views.setImageViewBitmap(R.id.imageView,bmp); views.setTextViewText(R.id.tv,currentBatteryLevel+"%"); ComponentName thisWidget=new ComponentName(this,NewBatteryWidget.class); /** 更新AppWidget */ manager.updateAppWidget(thisWidget, views); } public void onStart(Intent intent,int startId) { super.onStart(intent, startId); /** 注册接收器 */ registerReceiver(batteryReceiver,new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); /** 增加了对于POWER_CONNECTED和DISCONNECTED事件的监听, * 以实现充电时信息的动态变化,避免了原来需要依赖AlarmManager * 每隔一秒发送检测信息来实现,节约了电量,用原来隔一秒更新的方法, * 经过一夜测试,插件耗电量居然占到了8%,汗。。。 * * */ registerReceiver(powerConnectedReceiver,new IntentFilter(Intent.ACTION_POWER_CONNECTED)); registerReceiver(powerDisconnectedReceiver,new IntentFilter(Intent.ACTION_POWER_DISCONNECTED )); /** 使用AlarmManager实现,第一次启动Widget时隔一秒立即更新, * 以后均为两分钟发送一次更新提示信息,实现信息实时动态变化, * 实现节电功能 * */ long now=System.currentTimeMillis(); long pause; if(firstTimeToCreate) { firstTimeToCreate=false; pause=1000; } else { pause=1000*60*2; } Intent alarmIntent=new Intent(); alarmIntent=intent; PendingIntent pendingIntent=PendingIntent.getService(this, 0, alarmIntent, 0); AlarmManager alarm=(AlarmManager)getSystemService(Context.ALARM_SERVICE); alarm.set(AlarmManager.RTC_WAKEUP,now+pause,pendingIntent); setViews(); } } }
新的源码下载地址: http://download.csdn.net/detail/ritterliu/3794539 同样将在一周后将改为免费,谢谢大家。 原文地址:http://blog.csdn.net/ritterliu/article/details/6967206