最近做了一個Demo,監聽手機中傳感器的數據,並將數據保存到手機文件中,發現數據會有丟失的現象。
經過多次測試,發現系統進入深度休眠了,之后service會停止,雖然增加了service自動啟動的功能,但是還會導致數據中斷一段時間。如果屏幕一直亮着會比較耗電,所以亮屏這種方法直接Pass掉。那么怎么保證service一直運行不會中斷呢?
1,PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);通過Context.getSystemService()
.方法獲取PowerManager實例。
2,然后通過PowerManager的newWakeLock((int flags, String tag)來生成WakeLock實例。int Flags指示要獲取哪種WakeLock,不同的Lock對cpu 、屏幕、鍵盤燈有不同影響。
3,獲取WakeLock實例后通過acquire()獲取相應的鎖,然后進行其他業務邏輯的操作,最后使用release()釋放(釋放是必須的)。
關於int flags
各種鎖的類型對CPU 、屏幕、鍵盤的影響:
PARTIAL_WAKE_LOCK:保持CPU 運轉,屏幕和鍵盤燈有可能是關閉的。
SCREEN_DIM_WAKE_LOCK:保持CPU 運轉,允許保持屏幕顯示但有可能是灰的,允許關閉鍵盤燈
SCREEN_BRIGHT_WAKE_LOCK:保持CPU 運轉,允許保持屏幕高亮顯示,允許關閉鍵盤燈
FULL_WAKE_LOCK:保持CPU 運轉,保持屏幕高亮顯示,鍵盤燈也保持亮度
權限獲取
要進行電源的操作需要在AndroidManifest.xml中聲明該應用有設置電源管理的權限。
1 <uses-permission android:name="android.permission.WAKE_LOCK" />
另外WakeLock的設置是 Activiy 級別的,不是針對整個Application應用的。
在Android中,申請WakeLock可以讓進程持續執行即使手機進入睡眠模式,在Service的onCreate()方法中加入以下代碼,申請WakeLock:
1 WakeLock m_wklk; 2 3 @Override 4 public void onCreate() { 5 super.onCreate(); 6 PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); 7 m_wklk = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, DeviceSensorService.class.getName()); 8 m_wklk.acquire(); 9 //……………… 10 }
申請了WakeLock要記得釋放,否則手機可能無法進入休眠狀態。在onDestroy()方法中加入:
1 public void onDestroy() { 2 3 if (m_wklk != null) { 4 m_wklk.release(); 5 m_wklk = null; 6 } 7 };
完整的監聽sensor數據代碼如下:
1 /** 2 * 加速度傳感,陀螺儀,壓力傳感器,數據收集 3 * 4 */ 5 6 import java.text.SimpleDateFormat; 7 8 import android.app.Service; 9 import android.content.Context; 10 import android.content.Intent; 11 import android.hardware.Sensor; 12 import android.hardware.SensorEvent; 13 import android.hardware.SensorEventListener; 14 import android.hardware.SensorManager; 15 import android.os.IBinder; 16 import android.os.PowerManager; 17 import android.os.PowerManager.WakeLock; 18 import android.util.Log; 19 20 public class DeviceSensorService extends Service { 21 private static final String TAG = "DeviceSensorService"; 22 Sensor sensorAcc, sensoGyros, sensoPress; 23 SensorManager sm; 24 WakeLock m_wklk; 25 26 @Override 27 public void onCreate() { 28 super.onCreate(); 29 if (sm == null) { 30 sm = (SensorManager) getApplicationContext().getSystemService( 31 Context.SENSOR_SERVICE); 32 } 33 /*List<Sensor> sensors = sm.getSensorList(Sensor.TYPE_GYROSCOPE); 34 if (sensors.size() > 0){ 35 Sensor sensor = sensors.get(0); 36 sm.registerListener(this, 37 sensor, SensorManager.SENSOR_DELAY_NORMAL); 38 }*/ 39 40 // 加速度感應器 41 Sensor sensorAcc = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); 42 // 陀螺儀 43 Sensor sensoGyros = sm.getDefaultSensor(Sensor.TYPE_GYROSCOPE); 44 // 壓力 45 Sensor sensoPress = sm.getDefaultSensor(Sensor.TYPE_PRESSURE); 46 47 /* 48 * 最常用的一個方法 注冊事件 49 * 參數1 :SensorEventListener監聽器 50 * 參數2 :Sensor 一個服務可能有多個Sensor實現,此處調用getDefaultSensor獲取默認的Sensor 51 * 參數3 :模式 可選數據變化的刷新頻率,采樣率 52 * SENSOR_DELAY_FASTEST,100次左右 53 * SENSOR_DELAY_GAME,50次左右 54 * SENSOR_DELAY_UI,20次左右 55 * SENSOR_DELAY_NORMAL,5次左右 56 */ 57 sm.registerListener(mySensorListener, sensorAcc, 58 SensorManager.SENSOR_DELAY_NORMAL); //以普通采樣率注冊監聽器 59 sm.registerListener(mySensorListener, sensoGyros, 60 SensorManager.SENSOR_DELAY_NORMAL); 61 sm.registerListener(mySensorListener, sensoPress, 62 SensorManager.SENSOR_DELAY_NORMAL); 63 64 PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); 65 m_wklk = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, DeviceSensorService.class.getName()); 66 m_wklk.acquire(); 67 68 } 69 70 @Override 71 public IBinder onBind(Intent intent) { 72 return null; 73 } 74 75 @Override 76 public int onStartCommand(Intent intent, int flags, int startId) { 77 Log.i(TAG, "zhangjieqiong onStartCommand"); 78 // return super.onStartCommand(intent, flags, startId); 79 return Service.START_STICKY; 80 } 81 82 public void onDestroy() { 83 if (sm != null) { 84 sm.unregisterListener(mySensorListener); 85 mySensorListener = null; 86 } 87 if (m_wklk != null) { 88 m_wklk.release(); 89 m_wklk = null; 90 } 91 }; 92 93 /* 94 * SensorEventListener 接口的實現,需要實現兩個方法 95 * 方法1 onSensorChanged 當數據變化的時候被觸發調用 96 * 方法2 onAccuracyChanged 當獲得數據的精度發生變化的時候被調用,比如突然無法獲得數據時 97 */ 98 private SensorEventListener mySensorListener = new SensorEventListener() { 99 100 public void onSensorChanged(SensorEvent sensorEvent) { 101 synchronized (this) { 102 int type = sensorEvent.sensor.getType(); 103 104 SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss:SSS "); 105 String date = sDateFormat.format(new java.util.Date()); 106 107 switch (type) { 108 case Sensor.TYPE_ACCELEROMETER://加速度 109 // acc_count++; 110 float X_lateral = sensorEvent.values[0]; 111 float Y_longitudinal = sensorEvent.values[1]; 112 float Z_vertical = sensorEvent.values[2]; 113 MyLog.i("Accelerometer.txt", "Accelerometer", date + "," 114 + X_lateral + "," + Y_longitudinal + "," + Z_vertical 115 + ";"); 116 117 Log.i("sensor", "Accelerometer:"+ date + ", " 118 + X_lateral + "," + Y_longitudinal + "," + Z_vertical 119 + ";"); 120 121 break; 122 case Sensor.TYPE_GYROSCOPE://陀螺儀 123 // gyro_count++; 124 float X_laterals = sensorEvent.values[0]; 125 float Y_longitudinals = sensorEvent.values[1]; 126 float Z_verticals = sensorEvent.values[2]; 127 MyLog.i("Gyproscope.txt", "Gyproscope", date + "," 128 + X_laterals + "," + Y_longitudinals + "," 129 + Z_verticals + ";"); 130 Log.i("sensor", "Gyproscope:"+ date + ", " 131 + X_laterals + "," + Y_longitudinals + "," 132 + Z_verticals + ";"); 133 break; 134 case Sensor.TYPE_PRESSURE://壓力 135 // pres_count++; 136 float X_lateralss = sensorEvent.values[0]; 137 MyLog.i("Pressure.txt", "Pressure", date + "," + X_lateralss 138 + ";"); 139 Log.i("sensor", "Pressure:"+ date + "," + X_lateralss 140 + ";"); 141 break; 142 default: 143 break; 144 } 145 } 146 } 147 148 public void onAccuracyChanged(Sensor sensor, int accuracy) { 149 Log.i("sensor", "onAccuracyChanged-----sensor"+ sensor + ",acc:" + accuracy); 150 151 } 152 }; 153 }
關於保存數據到文件可以參考上一篇博客:http://www.cnblogs.com/zjqlogs/p/5488798.html
注:這樣處理會比較耗電。
參考:http://www.cnblogs.com/GnagWang/archive/2011/02/27/1966611.html
參考:http://blog.sina.com.cn/s/blog_474928c90100xpg9.html