如何从 GeoFire 中检索连续更新的位置数据并将其放在 Google 地图上?
how to retrieve continuous updated location data from the GeoFire and put it on Google map?
我正在开发一个儿童位置跟踪应用程序。在这里,我使用 geoFire 将孩子的位置发送到数据库中,geoFire 会在一定时间后更新。但问题是,在 parents activity 中,位置标记不会根据孩子的更新位置而改变......所以,我如何从数据库中检索连续的位置更新并移动标记符合位置??
这取决于您要显示的信息。
在下面的代码示例中,我将 ParentModel
、ChildModel
、LocationModel
和 CheckInModel
类 的实现留给了您发展。下面的代码也不处理初始化活动、Firebase 或 GoogleMaps
object.
不用说,您必须非常小心地保护这些敏感数据。
情形 1:Show/store 只有最后一个已知位置。
在这种情况下,数据库只为每个 child 保留一个位置。服务器上没有位置历史的概念。
这可以通过在单个位置侦听数据库中存储的数据的更新来实现(请参阅 Listen for Value Events). In the below code, I have also added an optional Polyline 显示地图打开时存储在客户端设备上的最近位置更新。每次数据在服务器上更新,监听器将被执行并更新地图的本地副本。
private DatabaseReference mDatabase;
private DatabaseReference mTrackedLocationRef;
private ParentModel mParent;
private ChildModel mSelectedChild;
private GoogleMap mMap;
private Polyline mCurrentLine;
private Marker mLastKnownLocationMarker;
// ...
mDatabase = FirebaseDatabase.getInstance().getReference();
// initialize a tracking line
mCurrentLine = mMap.addPolyline((new PolylineOptions())
.clickable(true);
// TODO: download parent's user profile to mParent
mSelectedChild = mParent.children[0]; // select first child
mTrackedLocationRef = mDatabase.child("locations").child(mSelectedChild.uid).child("lastKnownLocation");
ValueEventListener locationUpdateListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// location was updated
LocationModel locModel = dataSnapshot.getValue(LocationModel.class);
LatLng pos = locModel.getLatLng(); // getLatLng() returns a LatLng object.
// if enabled, add position to traced line
if (mCurrentLine != null) {
mCurrentLine.add(pos);
}
// update/create marker for last detected location
if (mLastKnownLocationMarker != null) {
mLastKnownLocationMarker.setPosition(pos);
} else {
mLastKnownLocationMarker = mMap.addMarker(new MarkerOptions().position(pos)
.title(mSelectedChild.firstName + "'s current location"));
}
// move camera to new position
googleMap.moveCamera(CameraUpdateFactory.newLatLng(pos));
}
@Override
public void onCancelled(DatabaseError databaseError) {
// Getting location update failed, log a message
Log.w(TAG, "locUpdate:onCancelled", databaseError.toException());
Toast.makeText(mContext, "Failed to load last known location.",
Toast.LENGTH_SHORT).show();
}
};
mTrackedLocationRef.addValueEventListener(locationUpdateListener);
场景 2:显示最后 5 个位置。
在这种情况下,位置 "check-ins" 的历史记录保存在使用 push()
操作上传到服务器的数据库中。在这种情况下,侦听器将仅使用 5 个最近的位置更新来更新地图。每次将新位置添加到服务器时,新位置将添加到地图中,并删除 5 个位置中最旧的位置。
private DatabaseReference mDatabase;
private DatabaseReference mTrackedLocationRef;
private ParentModel mParent;
private ChildModel mSelectedChild;
private GoogleMap mMap;
private Polyline mCurrentLine;
private final Map<String, Marker> mMarkers = new ConcurrentHashMap<String, Marker>();
// initialize a tracking line
mCurrentLine = mMap.addPolyline((new PolylineOptions())
.clickable(true);
// TODO: download parent's user profile to mParent
mSelectedChild = mParent.children[0]; // select first child
mTrackedLocationRef = mDatabase.child("locations").child(mSelectedChild.uid).child("checkins").limitToLast(5);
ChildEventListener locationUpdateListener = new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
// this location update is one of the five most-recent entries
String keyName = dataSnapshot.getKey();
Log.d(TAG, "onChildAdded:" + keyName);
CheckInModel checkin = dataSnapshot.getValue(CheckInModel.class);
LatLng pos = checkin.getLatLng(); // getLatLng() returns a LatLng object.
// remove title of previous marker
mMarkers.get(previousChildName).setTitle("");
// add new marker
Marker marker = mMap.addMarker(new MarkerOptions().position(pos)
.title(mSelectedChild.firstName + "'s current location"));
marker.setTag(keyName); // store key name in marker's metadata
// store marker by its key name for easy removal
mMarkers.put(keyName, marker);
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildChanged:" + dataSnapshot.getKey());
// todo: handle edited data?
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
// this location update is no longer one of the five most-recent entries
Log.d(TAG, "onChildRemoved:" + dataSnapshot.getKey());
// find and remove existing marker
mMarkers.get(dataSnapshot.getKey()).remove();
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildMoved:" + dataSnapshot.getKey());
// todo: handle reordered data?
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "locUpdate:onCancelled", databaseError.toException());
Toast.makeText(mContext, "Failed to load location history.",
Toast.LENGTH_SHORT).show();
}
};
mTrackedLocationRef.addChildEventListener(locationUpdateListener);
由于此数据本质上是敏感的,因此请确保您还拥有以快速简单的方式完全删除有关 parent 及其 children 的所有数据的流程。
我正在开发一个儿童位置跟踪应用程序。在这里,我使用 geoFire 将孩子的位置发送到数据库中,geoFire 会在一定时间后更新。但问题是,在 parents activity 中,位置标记不会根据孩子的更新位置而改变......所以,我如何从数据库中检索连续的位置更新并移动标记符合位置??
这取决于您要显示的信息。
在下面的代码示例中,我将 ParentModel
、ChildModel
、LocationModel
和 CheckInModel
类 的实现留给了您发展。下面的代码也不处理初始化活动、Firebase 或 GoogleMaps
object.
不用说,您必须非常小心地保护这些敏感数据。
情形 1:Show/store 只有最后一个已知位置。
在这种情况下,数据库只为每个 child 保留一个位置。服务器上没有位置历史的概念。
这可以通过在单个位置侦听数据库中存储的数据的更新来实现(请参阅 Listen for Value Events). In the below code, I have also added an optional Polyline 显示地图打开时存储在客户端设备上的最近位置更新。每次数据在服务器上更新,监听器将被执行并更新地图的本地副本。
private DatabaseReference mDatabase;
private DatabaseReference mTrackedLocationRef;
private ParentModel mParent;
private ChildModel mSelectedChild;
private GoogleMap mMap;
private Polyline mCurrentLine;
private Marker mLastKnownLocationMarker;
// ...
mDatabase = FirebaseDatabase.getInstance().getReference();
// initialize a tracking line
mCurrentLine = mMap.addPolyline((new PolylineOptions())
.clickable(true);
// TODO: download parent's user profile to mParent
mSelectedChild = mParent.children[0]; // select first child
mTrackedLocationRef = mDatabase.child("locations").child(mSelectedChild.uid).child("lastKnownLocation");
ValueEventListener locationUpdateListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// location was updated
LocationModel locModel = dataSnapshot.getValue(LocationModel.class);
LatLng pos = locModel.getLatLng(); // getLatLng() returns a LatLng object.
// if enabled, add position to traced line
if (mCurrentLine != null) {
mCurrentLine.add(pos);
}
// update/create marker for last detected location
if (mLastKnownLocationMarker != null) {
mLastKnownLocationMarker.setPosition(pos);
} else {
mLastKnownLocationMarker = mMap.addMarker(new MarkerOptions().position(pos)
.title(mSelectedChild.firstName + "'s current location"));
}
// move camera to new position
googleMap.moveCamera(CameraUpdateFactory.newLatLng(pos));
}
@Override
public void onCancelled(DatabaseError databaseError) {
// Getting location update failed, log a message
Log.w(TAG, "locUpdate:onCancelled", databaseError.toException());
Toast.makeText(mContext, "Failed to load last known location.",
Toast.LENGTH_SHORT).show();
}
};
mTrackedLocationRef.addValueEventListener(locationUpdateListener);
场景 2:显示最后 5 个位置。
在这种情况下,位置 "check-ins" 的历史记录保存在使用 push()
操作上传到服务器的数据库中。在这种情况下,侦听器将仅使用 5 个最近的位置更新来更新地图。每次将新位置添加到服务器时,新位置将添加到地图中,并删除 5 个位置中最旧的位置。
private DatabaseReference mDatabase;
private DatabaseReference mTrackedLocationRef;
private ParentModel mParent;
private ChildModel mSelectedChild;
private GoogleMap mMap;
private Polyline mCurrentLine;
private final Map<String, Marker> mMarkers = new ConcurrentHashMap<String, Marker>();
// initialize a tracking line
mCurrentLine = mMap.addPolyline((new PolylineOptions())
.clickable(true);
// TODO: download parent's user profile to mParent
mSelectedChild = mParent.children[0]; // select first child
mTrackedLocationRef = mDatabase.child("locations").child(mSelectedChild.uid).child("checkins").limitToLast(5);
ChildEventListener locationUpdateListener = new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
// this location update is one of the five most-recent entries
String keyName = dataSnapshot.getKey();
Log.d(TAG, "onChildAdded:" + keyName);
CheckInModel checkin = dataSnapshot.getValue(CheckInModel.class);
LatLng pos = checkin.getLatLng(); // getLatLng() returns a LatLng object.
// remove title of previous marker
mMarkers.get(previousChildName).setTitle("");
// add new marker
Marker marker = mMap.addMarker(new MarkerOptions().position(pos)
.title(mSelectedChild.firstName + "'s current location"));
marker.setTag(keyName); // store key name in marker's metadata
// store marker by its key name for easy removal
mMarkers.put(keyName, marker);
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildChanged:" + dataSnapshot.getKey());
// todo: handle edited data?
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
// this location update is no longer one of the five most-recent entries
Log.d(TAG, "onChildRemoved:" + dataSnapshot.getKey());
// find and remove existing marker
mMarkers.get(dataSnapshot.getKey()).remove();
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildMoved:" + dataSnapshot.getKey());
// todo: handle reordered data?
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "locUpdate:onCancelled", databaseError.toException());
Toast.makeText(mContext, "Failed to load location history.",
Toast.LENGTH_SHORT).show();
}
};
mTrackedLocationRef.addChildEventListener(locationUpdateListener);
由于此数据本质上是敏感的,因此请确保您还拥有以快速简单的方式完全删除有关 parent 及其 children 的所有数据的流程。