如何从 GeoFire 中检索持续更新的位置数据并将其放在 Google 地图上?

Posted

技术标签:

【中文标题】如何从 GeoFire 中检索持续更新的位置数据并将其放在 Google 地图上?【英文标题】:how to retrieve continuous updated location data from the GeoFire and put it on Google map? 【发布时间】:2020-03-10 15:02:30 【问题描述】:

我正在开发一个儿童位置跟踪应用程序。我正在使用 geoFire 将孩子的位置发送到数据库中,该位置会在一定时间后更新。但问题是,在父母活动中,位置标记不会根据孩子的更新位置而改变......那么,我怎样才能从数据库中检索连续的位置更新并根据位置移动标记?

【问题讨论】:

【参考方案1】:

这取决于您要显示的信息。

在下面的代码示例中,我将ParentModelChildModelLocationModelCheckInModel 类的实现留给您来开发。下面的代码也不处理初始化活动、Firebase 或GoogleMaps 对象。

不用说,您必须极其小心地保护这些敏感数据。

场景 1:仅显示/存储最后一个已知位置。

在这种情况下,数据库只为每个孩子保存一个位置。服务器上没有位置历史的概念。

这可以通过在单个位置监听存储在数据库中的数据的更新来实现(请参阅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);

场景 2:显示最后 5 个位置。

在这种情况下,位置“签入”的历史记录保存在使用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);


由于这些数据本质上是敏感的,因此请确保您还具有以快速简单的方式完全删除有关父母及其子女的所有数据的流程。

【讨论】:

抱歉我没听懂?您的示例是否适用于 GeoFire?因为我已经使用 GeoFire 存储了我的位置..

以上是关于如何从 GeoFire 中检索持续更新的位置数据并将其放在 Google 地图上?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用geofire从firebase获取位置

geofire android 存储和检索位置并将其显示在地图上

使用 GeoFire 将用户纬度和经度存储到我的数据库中 - 它没有持续更新

Firebase GeoFire,从我当前位置检索具有特定半径的帖子

如何在没有 Geofire 的情况下将位置对象保存在 Firebase 中?

Geofire 正在触发 onGeoQueryReady 而不是 onKeyEntered