最近做了一个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 }