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

how to retrieve continuous updated location data from the GeoFire and put it on Google map?

我正在开发一个儿童位置跟踪应用程序。在这里,我使用 geoFire 将孩子的位置发送到数据库中,geoFire 会在一定时间后更新。但问题是,在 parents activity 中,位置标记不会根据孩子的更新位置而改变......所以,我如何从数据库中检索连续的位置更新并移动标记符合位置??

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

在下面的代码示例中,我将 ParentModelChildModelLocationModelCheckInModel 类 的实现留给了您发展。下面的代码也不处理初始化活动、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 的所有数据的流程。