【发布时间】:2020-03-10 15:02:30
【问题描述】:
我正在开发一个儿童位置跟踪应用程序。我正在使用 geoFire 将孩子的位置发送到数据库中,该位置会在一定时间后更新。但问题是,在父母活动中,位置标记不会根据孩子的更新位置而改变......那么,我怎样才能从数据库中检索连续的位置更新并根据位置移动标记?
【问题讨论】:
标签: android google-maps firebase-realtime-database geofire
我正在开发一个儿童位置跟踪应用程序。我正在使用 geoFire 将孩子的位置发送到数据库中,该位置会在一定时间后更新。但问题是,在父母活动中,位置标记不会根据孩子的更新位置而改变......那么,我怎样才能从数据库中检索连续的位置更新并根据位置移动标记?
【问题讨论】:
标签: android google-maps firebase-realtime-database geofire
这取决于您要显示的信息。
在下面的代码示例中,我将ParentModel、ChildModel、LocationModel 和CheckInModel 类的实现留给您来开发。下面的代码也不处理初始化活动、Firebase 或GoogleMaps 对象。
不用说,您必须极其小心地保护这些敏感数据。
在这种情况下,数据库只为每个孩子保存一个位置。服务器上没有位置历史的概念。
这可以通过在单个位置监听存储在数据库中的数据的更新来实现(请参阅Listen for Value Events)。在下面的代码中,我还添加了一个可选的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);
在这种情况下,位置“签入”的历史记录保存在使用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);
【讨论】: