阅读前提:
下面将的是:你的App 在后台运行时:保证Service不被杀死的情况,静态是Activity 关闭Serice不关闭,动态注册广播是:随着窗体生命周期;
要想使Service在App关闭 后能够自启,必须root手机,让app成为系统app,这不是我们程序员干的事情---你想自己给自己装这样的系统,你可以试试,我不拿自己的手机开玩笑;还有QQ微信,能够自启动,那是因为手机系统里面有广播和对应Service 开启这两个,不然客户体验不好,就不会买这样的手机了。懂了吧。
======================
最近在做一个Demo,监听电量变化,持续记录电量的变化。
一开始我是在Activity中
注册广播,可以正常监听电量状态,但随着Activity生命周期变化,不能持续监听电量。就用service来持续监听,尝试了多次静态注册,发现竟然接收不到电量变化的广播。!!!!????
后来上网搜索,发现有
五个不能静态注册的广播,这里记录一下,免得下次再后知后觉的发现并惊讶于自己的笨拙。
不能静态注册的广播:
android.intent.action.SCREEN_ON
android.intent.action.SCREEN_OFF
android.intent.action.BATTERY_CHANGED
android.intent.action.CONFIGURATION_CHANGED
android.intent.acti
on.TIME_TICK
原因(有以下几种说法,提供给大家参考):
1.提高系统效率:这两个事件是android的基本事件,如果大多数程序监听,会大大的拖慢整个系统,所以android不鼓励我们在后台监听这两个事件。
2.因为有序广播的优先级问题。以上这些广播中,静态注册时,系统的优先级大于应用,并且系统阻止了广播的向下传播。又因在Android 的广播机制中,动态注册的优先级是要高于静态注册优先级的。故用动态注册代替静态注册。
3.系统安全问题。
解决方式(以android.intent.action.BATTERY_CHANGED为例):
动态注册不能放到activity中,因为动态注册必须要在activity消亡的时候调用unregisterReceiver,会随着activity的解锁消失而不能再接收广播。一般的办法是在activity起来后马上start一个service,这个service里动态注册一个broadcastreceiver,service必须常驻在系统内,所以要接收开机消息android.intent.action.BOOT_COMPLETED。
持续监听电量变化实例:
1,在Broadcast中启动service代码,开机自动启动:
private String boot_action ="android.intent.action.BOOT_COMPLETED"; @Override public void onReceive(Context context, Intent intent) { if(boot_action.equals(action)){ Log.i(TAG, "android.intent.action.BOOT_COMPLETED"); Intent in0 = new Intent(context, BatteryService.class); context.startService(in0); } }
不要忘记在Manifest.xml中注册开机启动广播:
1 <receiver android:name="BootBroadcastReceiver" > 2 <intent-filter> 3 <action android:name="android.intent.action.BOOT_COMPLETED" /> 4 intent-filter> 5 receiver>
2,在service中动态注册广播,处理电量,service停止后自动启动
1 import java.text.SimpleDateFormat; 2 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.BatteryManager; 9 import android.os.IBinder; 10 import android.util.Log; 11 12 public class BatteryService extends Service { 13 14 private static final String TAG = "BatteryReceiver"; 15 @Override 16 public IBinder onBind(Intent intent) { 17 return null; 18 } 19 20 @Override 21 public void onCreate() { 22 super.onCreate(); 23 Log.i(TAG, "onCreate--------------"); 24 IntentFilter batteryfilter = new IntentFilter(); 25 batteryfilter.addAction(Intent.ACTION_BATTERY_CHANGED); 26 registerReceiver(batteryReceiver, batteryfilter); 27 } 28 29 @Override 30 public void onStart(Intent intent, int startId) { 31 super.onStart(intent, startId); 32 } 33 34 @Override 35 public int onStartCommand(Intent intent, int flags, int startId) { 36 Log.i(TAG, "onStartCommand--------------"); 37 return Service.START_STICKY; // 38 } 39 40 @Override 41 public void onDestroy() { 42 Log.i(TAG, "onDestroy--------------"); 43 super.onDestroy(); 44 this.unregisterReceiver(batteryReceiver); 45 46 } 47 // 接收电池信息更新的广播 48 private BroadcastReceiver batteryReceiver = new BroadcastReceiver(){ 49 @Override 50 public void onReceive(Context context, Intent intent) { 51 Log.i(TAG, "BatteryReceiver--------------"); 52 String action = intent.getAction(); 53 Log.i(TAG, " 0 action:"+ action); 54 Log.i(TAG, "ACTION_BATTERY_CHANGED"); 55 int status = intent.getIntExtra("status", 0); 56 int health = intent.getIntExtra("health", 0); 57 boolean present = intent.getBooleanExtra("present", false); 58 int level = intent.getIntExtra("level", 0); 59 int scale = intent.getIntExtra("scale", 0); 60 int icon_small = intent.getIntExtra("icon-small", 0); 61 int plugged = intent.getIntExtra("plugged", 0); 62 int voltage = intent.getIntExtra("voltage", 0); 63 int temperature = intent.getIntExtra("temperature", 0); 64 String technology = intent.getStringExtra("technology"); 65 66 String statusString = ""; 67 switch (status) { 68 case BatteryManager.BATTERY_STATUS_UNKNOWN: 69 statusString = "unknown"; 70 break; 71 case BatteryManager.BATTERY_STATUS_CHARGING: 72 statusString = "charging"; 73 break; 74 case BatteryManager.BATTERY_STATUS_DISCHARGING: 75 statusString = "discharging"; 76 break; 77 case BatteryManager.BATTERY_STATUS_NOT_CHARGING: 78 statusString = "not charging"; 79 break; 80 case BatteryManager.BATTERY_STATUS_FULL: 81 statusString = "full"; 82 break; 83 } 84 String acString = ""; 85 86 switch (plugged) { 87 case BatteryManager.BATTERY_PLUGGED_AC: 88 acString = "plugged ac"; 89 break; 90 case BatteryManager.BATTERY_PLUGGED_USB: 91 acString = "plugged usb"; 92 break; 93 } 94 95 SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss:SSS "); 96 String date = sDateFormat.format(new java.util.Date()); 97 98 Log.i(TAG, "battery: date=" + date + ",status " + statusString 99 + ",level=" + level +",scale=" + scale 100 + ",voltage=" + voltage +",acString=" + acString ); 101 102 MyLog.i("Battery.txt", "Battery",":date=" + date + ",status=" + statusString 103 + ",level=" + level +",scale=" + scale 104 + ",voltage=" + voltage ); 105 106 } 107 }; 108 }
那么怎样才能保证service不被杀死?
Android开发的过程中,每次调用startService(Intent)的时候,都会调用该Service对象的onStartCommand(Intent,int,int)方法,这里在onStartCommand方法的返回值做文章就可以了,这里用到的是Service.START_STICKY这个返回值:
网络上找到的解释:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。
3,将电量数据保存到文件中(这里只提取了关键的方法)
1 /** 2 * 打开日志文件并写入日志 3 * 4 * @return 5 * **/ 6 private static void writeLogtoFile(String logTypename, String mylogtype, 7 String tag, String text) {// 新建或打开日志文件 8 Log.i("zjq", "mylog----------"); 9 File path = Environment.getExternalStorageDirectory(); 10 Date nowtime = new Date(); 11 String needWriteFiel = logfile.format(nowtime); 12 String needWriteMessage = text; 13 File file = new File(path, needWriteFiel + logTypename); 14 try { 15 FileWriter filerWriter = new FileWriter(file, true);// 后面这个参数代表是不是要接上文件中原来的数据,不进行覆盖 16 BufferedWriter bufWriter = new BufferedWriter(filerWriter); 17 bufWriter.write(needWriteMessage); 18 bufWriter.newLine(); 19 bufWriter.close(); 20 filerWriter.close(); 21 } catch (IOException e) { 22 e.printStackTrace(); 23 } 24 }