Android Widget 电池插件的开发实现

最近突发奇想,想自己编一个Android电池插件放在桌面上,一是这个App确实有它的实用价值,二是编起来工程量应该不是很大,不用花太长时间,三来又能学习下Widget的开发方法,一举三得,于是,暂停下游戏开发的学习,来编一个widget先。 
    在查找并结合多方资料后终于实现,效果图如下: 
长按桌面空白处,出现菜单,点击Widgets,此时的插件已经装入: 

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

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

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

 

下面介绍代码的实现: 

整个工程主要实现两个部分,一个是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



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值