我的目标
要构建允许用户打开和关闭位置跟踪的应用。启用跟踪后,我想将用户的位置数据推送到Firebase。
我尝试的解决方案
我使用PendingIntent和Google Play服务FusedLocationAPI在后台跟踪位置。在每次位置更新(以30秒为标点)时,PendingIntent都会向WakefulBroadcastReceiver触发一个意图(如果有位置更新)。然后WakefulBroadcastReceiver应该将位置数据保存到Firebase。
这是WakefulBroadcastReceiver的样子:
public class LocationProcessingReceiver extends WakefulBroadcastReceiver {
private static final String TAG = "LocationProcessingRcv";
@Override
public void onReceive(Context context, Intent intent) {
if (LocationResult.hasResult(intent)) {
Log.i(this.TAG, "Received location result");
// Extract location from result and push to server
Location location = LocationResult.extractResult(intent).getLastLocation();
this.pushLocationToServer(location, intent.getStringExtra("userId"));
}
else {
Log.i(TAG, "No location result");
}
}
/**
* Pushes location to Firebase server
* @param location
*/
private void pushLocationToServer(Location location, String userId) {
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance();
// Data to update the latest status of the user
Map<String, Object> statusMap = new HashMap<String, Object>();
// ... various statusMap.put(...) calls go here
// Get reference to Firebase as well as key at which to update reference
DatabaseReference dbRef = FirebaseDatabase.getInstance().getReference();
dbRef.child(DB_LOC_HISTORY_REFERENCE).push().updateChildren(historyMap, new DatabaseReference.CompletionListener() {
@Override
public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
if (databaseError == null) {
Log.i(TAG, "Successfully pushed to server");
}
else {
Log.i(TAG, "Server push failed: " + databaseError.toString());
}
}
});
}
}
问题
在某些电话上,从不调用onComplete回调(在某些设备上!)。我不知道为什么这不起作用...在某些设备上,回调正常工作。在其他情况下,永远不会收到回调,而且我也永远不会在Firebase中看到更新的数据。
日志显示位置更新工作正常,并且按预期方式定期调用WakefulBroadcastReceiver的onReceive()方法。
我本来希望onComplete被调用,但是如果存在连接问题,则会显示一个错误。但这永远不会发生,我正在努力了解原因。
注意事项:这些设备中的许多都在3G上运行。当我的应用程序在后台运行时,是否有可能因为3G连接速度太慢而在Firebase完成此操作之前杀死了BroadcastReceiver?
最佳答案
该问题可能与BroadcastReceiver的生命周期有关。
该文档说明:
BroadcastReceiver对象仅在通话期间有效
到onReceive(Context,Intent)。一旦您的代码从这里返回
功能,系统认为该对象已完成且不再
活性。
这对您可以在
onReceive(Context,Intent)实现:需要的任何东西
异步操作不可用,因为您将需要
从函数返回以处理异步操作,但在
这时BroadcastReceiver不再处于活动状态,因此
系统在异步操作之前可以随意终止其进程
完成。
由于FirebaseDatabase操作是在后台线程上异步执行的,因此在某些情况下,系统将在执行DB操作之前销毁LocationProcessingReceiver
实例。
您可能认为使用WakefulBroadcastReceiver可以防止接收器对象过早损坏,但事实并非如此。 WakefulBroadcastReceiver
旨在用于安全地启动服务,您在此处无需执行此操作。这没有任何好处。请改用BroadcastReceiver
。
为确保允许完成DB操作,请在pushLocationToServer()
中获取一个Wakelock(可能出于安全考虑可能会超时),然后在onComplete()
回调中释放它。