Android GPS 服务唤醒锁
Android Wakelock for GPS Service
我正在开发一个应用程序,它每十分钟获取一次 GPS 位置并将其发送到服务器,为此我使用了计时器、requestLocationUpdates 和 Android 异步 Http 客户端库。位置需要每十分钟最多保存 12 小时。
为了让应用程序保持活动状态,我在服务内的 onCreate 中使用唤醒锁
PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "whatever");
wl.acquire();
和 onDestroy()
wl.release();
通过 MainActivity 中的按钮启动和停止服务。我的主要问题是,如果用户按下主页按钮并将应用程序移回,我只会获得两次位置(开始时和 10 分钟后,20 分钟后没有位置更新)。好像只要在应用上锁屏就可以了,但是当我锁在主屏幕上几分钟后进程似乎被杀死了。
这是我的 GPS 服务的完整代码:
public class UpdatePositionService extends Service {
private PowerManager.WakeLock wl;
private Handler mHandler = new Handler(Looper.getMainLooper());
private AsyncHttpClient client = new AsyncHttpClient();
private SharedPreferences preferences;
public static final String USER_PREFERENCES = "userPreferences";
private Timer updatingTimer;
private TimerTask task = new TimerTask() {
@Override
public void run() {
mHandler.post(new Runnable() {
public void run() {
preferences = getSharedPreferences(USER_PREFERENCES, MODE_PRIVATE);
final String uid = preferences.getString("userid", "");
final String pause = readFromFile("pause.txt");
final String userState = readFromFile("user.txt");
final String workid = readFromFile("work.txt");
final String consid = readFromFile("cons.txt");
if (!pause.equals("1") && !userState.equals("0")) {
Log.e("mmd:test:123", "dochodzi " + userState);
final LocationManager[] lm = {(LocationManager)
getSystemService(Context.LOCATION_SERVICE)};
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setPowerRequirement(Criteria.POWER_HIGH);
_if();
lm[0].requestLocationUpdates(LocationManager
.GPS_PROVIDER, 6000, 10, new LocationListener() {
@Override
public void onLocationChanged(Location location) {
String updatedPause = readFromFile("pause.txt");
_if();
lm[0].removeUpdates(this);
lm[0] = null;
if (!updatedPause.equals("1")) {
RequestParams params = new RequestParams();
params.put("uid", uid);
params.put("lat", location.getLatitude());
params.put("long", location.getLongitude());
params.put("workid", workid);
params.put("type", userState);
params.put("cons", consid);
String url = "http://example.com/api/event/add";
client.post(url, params,
new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int statusCode,
Header[] headers, byte[] responseBody) {
String response = new String(
responseBody);
if (!response.equals("ERROR")) {
} else {
}
}
@Override
public void onFailure(
int statusCode, Header[] headers,
byte[] responseBody,
Throwable error) {}
});
}
}
@Override
public void onStatusChanged(String provider, int
status, Bundle extras) {}
@Override
public void onProviderEnabled(String provider) {}
@Override
public void onProviderDisabled(String provider) {}
});
}
}
});
}
};
private void _if() {
if (ActivityCompat.checkSelfPermission(UpdatePositionService.this,
Manifest.permission.ACCESS_FINE_LOCATION) !=
PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(UpdatePositionService.this,
Manifest.permission.ACCESS_COARSE_LOCATION) !=
PackageManager.PERMISSION_GRANTED) {}
}
@Override
public void onCreate() {
super.onCreate();
updatingTimer = new Timer();
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager
.ACQUIRE_CAUSES_WAKEUP, "whatever");
wl.acquire();
}
@Override
public void onDestroy() {
updatingTimer.cancel();
mHandler.removeCallbacksAndMessages(null);
wl.release();
super.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
int time = 1000 * 60 * 10; // 10 mins
updatingTimer.scheduleAtFixedRate(task, 3000, time);
return START_NOT_STICKY;
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
private String readFromFile(String filename) {
String ret = "";
try {
InputStream inputStream = openFileInput(filename);
if (inputStream != null) {
InputStreamReader inputStreamReader = new InputStreamReader
(inputStream);
BufferedReader bufferedReader = new BufferedReader
(inputStreamReader);
String receiveString = "";
StringBuilder stringBuilder = new StringBuilder();
while ((receiveString = bufferedReader.readLine()) != null) {
stringBuilder.append(receiveString);
}
inputStream.close();
ret = stringBuilder.toString();
}
} catch (FileNotFoundException e) {
Log.e("login activity", "File not found: " + e.toString());
} catch (IOException e) {
Log.e("login activity", "Can not read file: " + e.toString());
}
return ret;
}
}
扩展@CommonsWare 。为此设置服务是个坏主意——而且也不像您所看到的那样工作。 Android 杀了它,派对结束了。要执行任何周期性任务,您必须使用警报管理器设置警报。要做到这一点,请注册一个警报 - 在某些设置为在启动时接收的接收器中更好 - 因为在重新启动时,所有警报都会再见:
private void setupAlarm(Context context, boolean setup) {
am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
pi = PendingIntent.getBroadcast(context, NOT_USED, yourIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
if (setup) { // setup the alarms
try {
am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + SOME_DELAY, THE_INTERVAL_BETWEEN_ALARMS, pi);
} catch (InstantiationException e) {
// should not happen
throw new RuntimeException(UNABLE_TO_SET_ALARMS, e);
} catch (IllegalAccessException e) {
// should not happen
throw new RuntimeException(UNABLE_TO_SET_ALARMS, e);
}
} else { // teardown the alarms
// send message to the monitors that the party is over
Intent i = new Intent(YOUR_ABORTING_ACTION, Uri.EMPTY, context, YOUR_SERVICE_CLASS);
WakefulIntentService.sendWakefulWork(context, i);
// cancel the alarms
am.cancel(pi);
}
d("alarms " + (setup ? "enabled" : "disabled"));
}
然后在注册接收来自 AlarmManager 的广播的接收器的 onReceive 中(它们为您保留永远不会失败的唤醒锁)委托给 WakefulIntentService
@Override
final public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (ac_setup_alarm.equals(action) || ac_cancel_alarm.equals(action)) {
monitoringIntent = new Intent(context, this.getClass());
monitoringIntent.setAction(ac_monitor.toString());
final boolean enable = ac_setup_alarm.equals(action);
setupAlarm(context, enable);
} else if (ac_monitor.equals(action)) {
// monitoring - got broadcast from ALARM
WakefulIntentService.sendWakefulWork(context, YOUR_SERVICE_CLASS);
} else if (ac_reschedule_alarm.equals(action)) {
monitoringIntent = new Intent(context, this.getClass());
monitoringIntent.setAction(ac_monitor.toString());
rescheduleAlarm(context);
} else {
w("Received bogus intent : " + intent);
}
}
或者,要使用唤醒意图服务,您可以使用 WakefulBroadcastReceiver - but you have to write the service. The (my) code is here - 有效!
我正在开发一个应用程序,它每十分钟获取一次 GPS 位置并将其发送到服务器,为此我使用了计时器、requestLocationUpdates 和 Android 异步 Http 客户端库。位置需要每十分钟最多保存 12 小时。
为了让应用程序保持活动状态,我在服务内的 onCreate 中使用唤醒锁
PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "whatever");
wl.acquire();
和 onDestroy()
wl.release();
通过 MainActivity 中的按钮启动和停止服务。我的主要问题是,如果用户按下主页按钮并将应用程序移回,我只会获得两次位置(开始时和 10 分钟后,20 分钟后没有位置更新)。好像只要在应用上锁屏就可以了,但是当我锁在主屏幕上几分钟后进程似乎被杀死了。
这是我的 GPS 服务的完整代码:
public class UpdatePositionService extends Service {
private PowerManager.WakeLock wl;
private Handler mHandler = new Handler(Looper.getMainLooper());
private AsyncHttpClient client = new AsyncHttpClient();
private SharedPreferences preferences;
public static final String USER_PREFERENCES = "userPreferences";
private Timer updatingTimer;
private TimerTask task = new TimerTask() {
@Override
public void run() {
mHandler.post(new Runnable() {
public void run() {
preferences = getSharedPreferences(USER_PREFERENCES, MODE_PRIVATE);
final String uid = preferences.getString("userid", "");
final String pause = readFromFile("pause.txt");
final String userState = readFromFile("user.txt");
final String workid = readFromFile("work.txt");
final String consid = readFromFile("cons.txt");
if (!pause.equals("1") && !userState.equals("0")) {
Log.e("mmd:test:123", "dochodzi " + userState);
final LocationManager[] lm = {(LocationManager)
getSystemService(Context.LOCATION_SERVICE)};
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setPowerRequirement(Criteria.POWER_HIGH);
_if();
lm[0].requestLocationUpdates(LocationManager
.GPS_PROVIDER, 6000, 10, new LocationListener() {
@Override
public void onLocationChanged(Location location) {
String updatedPause = readFromFile("pause.txt");
_if();
lm[0].removeUpdates(this);
lm[0] = null;
if (!updatedPause.equals("1")) {
RequestParams params = new RequestParams();
params.put("uid", uid);
params.put("lat", location.getLatitude());
params.put("long", location.getLongitude());
params.put("workid", workid);
params.put("type", userState);
params.put("cons", consid);
String url = "http://example.com/api/event/add";
client.post(url, params,
new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int statusCode,
Header[] headers, byte[] responseBody) {
String response = new String(
responseBody);
if (!response.equals("ERROR")) {
} else {
}
}
@Override
public void onFailure(
int statusCode, Header[] headers,
byte[] responseBody,
Throwable error) {}
});
}
}
@Override
public void onStatusChanged(String provider, int
status, Bundle extras) {}
@Override
public void onProviderEnabled(String provider) {}
@Override
public void onProviderDisabled(String provider) {}
});
}
}
});
}
};
private void _if() {
if (ActivityCompat.checkSelfPermission(UpdatePositionService.this,
Manifest.permission.ACCESS_FINE_LOCATION) !=
PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(UpdatePositionService.this,
Manifest.permission.ACCESS_COARSE_LOCATION) !=
PackageManager.PERMISSION_GRANTED) {}
}
@Override
public void onCreate() {
super.onCreate();
updatingTimer = new Timer();
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager
.ACQUIRE_CAUSES_WAKEUP, "whatever");
wl.acquire();
}
@Override
public void onDestroy() {
updatingTimer.cancel();
mHandler.removeCallbacksAndMessages(null);
wl.release();
super.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
int time = 1000 * 60 * 10; // 10 mins
updatingTimer.scheduleAtFixedRate(task, 3000, time);
return START_NOT_STICKY;
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
private String readFromFile(String filename) {
String ret = "";
try {
InputStream inputStream = openFileInput(filename);
if (inputStream != null) {
InputStreamReader inputStreamReader = new InputStreamReader
(inputStream);
BufferedReader bufferedReader = new BufferedReader
(inputStreamReader);
String receiveString = "";
StringBuilder stringBuilder = new StringBuilder();
while ((receiveString = bufferedReader.readLine()) != null) {
stringBuilder.append(receiveString);
}
inputStream.close();
ret = stringBuilder.toString();
}
} catch (FileNotFoundException e) {
Log.e("login activity", "File not found: " + e.toString());
} catch (IOException e) {
Log.e("login activity", "Can not read file: " + e.toString());
}
return ret;
}
}
扩展@CommonsWare
private void setupAlarm(Context context, boolean setup) {
am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
pi = PendingIntent.getBroadcast(context, NOT_USED, yourIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
if (setup) { // setup the alarms
try {
am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + SOME_DELAY, THE_INTERVAL_BETWEEN_ALARMS, pi);
} catch (InstantiationException e) {
// should not happen
throw new RuntimeException(UNABLE_TO_SET_ALARMS, e);
} catch (IllegalAccessException e) {
// should not happen
throw new RuntimeException(UNABLE_TO_SET_ALARMS, e);
}
} else { // teardown the alarms
// send message to the monitors that the party is over
Intent i = new Intent(YOUR_ABORTING_ACTION, Uri.EMPTY, context, YOUR_SERVICE_CLASS);
WakefulIntentService.sendWakefulWork(context, i);
// cancel the alarms
am.cancel(pi);
}
d("alarms " + (setup ? "enabled" : "disabled"));
}
然后在注册接收来自 AlarmManager 的广播的接收器的 onReceive 中(它们为您保留永远不会失败的唤醒锁)委托给 WakefulIntentService
@Override
final public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (ac_setup_alarm.equals(action) || ac_cancel_alarm.equals(action)) {
monitoringIntent = new Intent(context, this.getClass());
monitoringIntent.setAction(ac_monitor.toString());
final boolean enable = ac_setup_alarm.equals(action);
setupAlarm(context, enable);
} else if (ac_monitor.equals(action)) {
// monitoring - got broadcast from ALARM
WakefulIntentService.sendWakefulWork(context, YOUR_SERVICE_CLASS);
} else if (ac_reschedule_alarm.equals(action)) {
monitoringIntent = new Intent(context, this.getClass());
monitoringIntent.setAction(ac_monitor.toString());
rescheduleAlarm(context);
} else {
w("Received bogus intent : " + intent);
}
}
或者,要使用唤醒意图服务,您可以使用 WakefulBroadcastReceiver - but you have to write the service. The (my) code is here - 有效!