Java 通过实时lat&;更改标记位置;没有添加新标记的Firebase数据库中的lang

Java 通过实时lat&;更改标记位置;没有添加新标记的Firebase数据库中的lang,java,android,firebase-realtime-database,google-maps-markers,Java,Android,Firebase Realtime Database,Google Maps Markers,我的实时Firebase数据库 我试着在某个时候改变很多lat Lang的位置,就像uber中的汽车一样, 但当我改变lat或lang或两者都改变时,这不会改变标记的位置,而是会产生一个新的标记。例如,我想在实时数据库中更改lat时,标记也会根据该lat的值进行更改 我试着创造条件 `if (marker != null) setPosition else "marker == null"` add new marker 但问题是我有>1个标记,因此此解决方案是在地

我的实时Firebase数据库

我试着在某个时候改变很多lat Lang的位置,就像uber中的汽车一样, 但当我改变lat或lang或两者都改变时,这不会改变标记的位置,而是会产生一个新的标记。例如,我想在实时数据库中更改lat时,标记也会根据该lat的值进行更改

我试着创造条件

`if (marker != null) 
    setPosition 
 else "marker == null"` 
    add new marker 
但问题是我有>1个标记,因此此解决方案是在地图上仅显示一个标记,因为标记!=空的

public class Map extends FragmentActivity implements OnMapReadyCallback {
FirebaseDatabase database;
DatabaseReference myRef;
GoogleMap mMap;
MarkerOptions options;
Marker mCurrLocationMarker;
LatLng ll;
model save;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_map);
    // Obtain the SupportMapFragment and get notified when the map is ready to be used.
    SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
            .findFragmentById(R.id.map);
    mapFragment.getMapAsync(this);
}

  @Override
public void onMapReady(GoogleMap googleMap) {
    mMap = googleMap;

    database = FirebaseDatabase.getInstance();
    myRef = database.getReference("user");

    myRef.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            for (DataSnapshot ds : dataSnapshot.getChildren()) {

                Double lang = ds.child("lang").getValue(Double.class);
                Double lat = ds.child("lat").getValue(Double.class);
                save = new model(lat, lang);
                ll = new LatLng(save.getLat(), save.getLang());

                mCurrLocationMarker = mMap.addMarker(options
                        .position(ll));

            }

        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });
}
当我在firebase中更改实时lat和lang时,我希望标记的位置已更改,但结果是创建了另一个标记。

试试这个

您必须在mapreadycallback上实现

@Override
public void onMapReady(GoogleMap googleMap) {
    mMap = googleMap;

}
和mMap使私有或公共变量

在调用循环方法之前

插入以下代码

mMap.clear();
您对addValueEventListener使用了错误的方式

您可以在onCreate方法中提交addValueEventlistener,并且在调用之前还需要检查null


在OnMapReadyCallback方法中,仅绑定mMap变量。

请使用以下Kotlin代码查看标记的完整跟踪、动画和移动,如uber:

首先添加firebase侦听器

mFirebaseRef?.child(mDriverId)!!.addChildEventListener(listener);
 var listener = object : ChildEventListener {
    override fun onCancelled(p0: DatabaseError) {
        Log.e("onCancelled", " " + p0.message)
    }

    override fun onChildMoved(p0: DataSnapshot, p1: String?) {
        Log.e("onChildMoved", " " + p0.key)
    }

    override fun onChildChanged(dataSnapshot: DataSnapshot, p1: String?) {
        Log.e("onChildChanged", " " + dataSnapshot.key)

      //Write your database reference login for getting Lat Lng

        if (dataSnapshot.key.equals("l")) {
            val latLatLng = dataSnapshot.value as ArrayList<Any>?
            if (latLatLng!!.size == 2) {
                displayLocation(latLatLng) 
            }
        }
    }

    override fun onChildAdded(p0: DataSnapshot, p1: String?) {
        Log.e("onChildAdded", " " + p0.key)
    }

    override fun onChildRemoved(p0: DataSnapshot) {
        Log.e("onChildRemoved", " " + p0.key)
    }
}
private var markerCount: Int = 0
private var marker: Marker? = null;
private var mLastLocation: Location? = null

fun addMarker(googleMap: GoogleMap?, lat: Double, lon: Double) {

    if (markerCount == 1) {

        try {
            try {
                animateMarker(marker!!, LatLng(mLastLocation!!.latitude, mLastLocation!!.longitude))
             } catch (e: Exception) {
            }

        } catch (e: Exception) {
            e.printStackTrace()
        }

    } else if (markerCount == 0) {

        var pickUpBmp: Bitmap = BitmapFactory.decodeResource(resources, R.drawable.carbike)
        mMap = googleMap
        val latlong = LatLng(lat, lon)
        marker = mMap!!.addMarker(MarkerOptions().position(LatLng(lat, lon))
                .icon(BitmapDescriptorFactory.fromBitmap(pickUpBmp))
                .anchor(0.5f, 0.5f)
                .flat(false))
        mMap!!.moveCamera(CameraUpdateFactory.newLatLngZoom(latlong, MAP_ZOOM_LEVEL))

        markerCount = 1

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return
        }
    }
}
定义firebase侦听器

mFirebaseRef?.child(mDriverId)!!.addChildEventListener(listener);
 var listener = object : ChildEventListener {
    override fun onCancelled(p0: DatabaseError) {
        Log.e("onCancelled", " " + p0.message)
    }

    override fun onChildMoved(p0: DataSnapshot, p1: String?) {
        Log.e("onChildMoved", " " + p0.key)
    }

    override fun onChildChanged(dataSnapshot: DataSnapshot, p1: String?) {
        Log.e("onChildChanged", " " + dataSnapshot.key)

      //Write your database reference login for getting Lat Lng

        if (dataSnapshot.key.equals("l")) {
            val latLatLng = dataSnapshot.value as ArrayList<Any>?
            if (latLatLng!!.size == 2) {
                displayLocation(latLatLng) 
            }
        }
    }

    override fun onChildAdded(p0: DataSnapshot, p1: String?) {
        Log.e("onChildAdded", " " + p0.key)
    }

    override fun onChildRemoved(p0: DataSnapshot) {
        Log.e("onChildRemoved", " " + p0.key)
    }
}
private var markerCount: Int = 0
private var marker: Marker? = null;
private var mLastLocation: Location? = null

fun addMarker(googleMap: GoogleMap?, lat: Double, lon: Double) {

    if (markerCount == 1) {

        try {
            try {
                animateMarker(marker!!, LatLng(mLastLocation!!.latitude, mLastLocation!!.longitude))
             } catch (e: Exception) {
            }

        } catch (e: Exception) {
            e.printStackTrace()
        }

    } else if (markerCount == 0) {

        var pickUpBmp: Bitmap = BitmapFactory.decodeResource(resources, R.drawable.carbike)
        mMap = googleMap
        val latlong = LatLng(lat, lon)
        marker = mMap!!.addMarker(MarkerOptions().position(LatLng(lat, lon))
                .icon(BitmapDescriptorFactory.fromBitmap(pickUpBmp))
                .anchor(0.5f, 0.5f)
                .flat(false))
        mMap!!.moveCamera(CameraUpdateFactory.newLatLngZoom(latlong, MAP_ZOOM_LEVEL))

        markerCount = 1

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return
        }
    }
}
最后,只需使用以下方法设置标记的动画:

fun animateMarker( marker: Marker,toPosition: LatLng) {
    val handler = Handler()
    val start = SystemClock.uptimeMillis()
    val proj = mMap!!.getProjection()
    val startPoint = proj.toScreenLocation(marker.getPosition())
    val startLatLng = proj.fromScreenLocation(startPoint)
    val duration: Long = 3000

    val interpolator = LinearInterpolator()

    handler.post(object : Runnable {
        override fun run() {
            val elapsed = SystemClock.uptimeMillis() - start
            val t = interpolator.getInterpolation(elapsed.toFloat() / duration)
            val lng = t * toPosition.longitude + (1 - t) * startLatLng.longitude
            val lat = t * toPosition.latitude + (1 - t) * startLatLng.latitude
            marker.position = LatLng(lat, lng)
            marker.rotation = (getBearingBetweenTwoPoints1(startLatLng, toPosition).toString().toFloat())

            runOnUiThread(Runnable {
                mMap!!.moveCamera(CameraUpdateFactory
                        .newCameraPosition(CameraPosition.Builder()
                                .target(toPosition)
                                .zoom(MAP_ZOOM_LEVEL)
                                .build()))
            })

            if (t < 1.0) {
                handler.postDelayed(this, 16)
            }
        }
    })
}
如果您熟悉Kotlin,我希望这将对您有所帮助:)

@mohamedgaber无需混淆,只需像这样更新您的侦听器,它将适用于多个孩子(标记),而不是单个标记(确保您的标记不同)。只要在Koltin中转换这个监听器,并使用我提供的其他代码,我保证它会像Uber一样顺利工作

 myRef.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        for (DataSnapshot ds : dataSnapshot.getChildren()) {

            Double lang = ds.child("lang").getValue(Double.class);
            Double lat = ds.child("lat").getValue(Double.class);
            save = new model(lat, lang);
            ll = new LatLng(save.getLat(), save.getLang());

            displayLocation(ll) 

       }
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {

    }
});

根据我对其他答案的评论,以下是我根据你的问题得出的结论

此代码将在地图上显示多个标记,但在数据库中的
/users
下,每个ID仅显示一个标记。如果特定ID的位置发生更改,则其关联的标记将被移动,而不会影响地图上的其他标记

警告:以下代码将实时更新您的地图。根据您的数据更改频率,您可能需要缓存新的标记位置,并且仅每隔2-5秒左右更新一次

在深入了解代码之前,请注意以下几点:

public class Map extends FragmentActivity implements OnMapReadyCallback {
    FirebaseDatabase database;
    DatabaseReference userLocationsRef;
    GoogleMap mMap;

    Map<String, Marker> mNamedMarkers = new HashMap<String,Marker>();

    ChildEventListener markerUpdateListener = new ChildEventListener() {

            /**
             * Adds each existing/new location of a marker.
             *
             * Will silently update any existing markers as needed.
             * @param dataSnapshot  The new location data
             * @param previousChildName  The key of the previous child event
             */
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
                    String key = dataSnapshot.getKey();
                    Log.d(TAG, "Adding location for '" + key + "'");

                    Double lng = ds.child("lang").getValue(Double.class);
                    Double lat = ds.child("lat").getValue(Double.class);
                    LatLng location = new LatLng(lat, lng);

                    Marker marker = mNamedMarkers.get(key);

                    if (marker == null) {
                        MarkerOptions options = getMarkerOptions(key);
                        marker = mMap.addMarker(options.position(location));
                        mNamedMarkers.put(key, marker);
                    } else {
                        // This marker-already-exists section should never be called in this listener's normal use, but is here to handle edge cases quietly.
                        // TODO: Confirm if marker title/snippet needs updating.
                        marker.setPosition(location);
                    }
            }

            /**
             * Updates the location of a previously loaded marker.
             *
             * Will silently create any missing markers as needed.
             * @param dataSnapshot  The new location data
             * @param previousChildName  The key of the previous child event
             */
            @Override
            public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
                    String key = dataSnapshot.getKey();
                    Log.d(TAG, "Location for '" + key + "' was updated.");

                    Double lng = ds.child("lang").getValue(Double.class);
                    Double lat = ds.child("lat").getValue(Double.class);
                    LatLng location = new LatLng(lat, lng);

                    Marker marker = mNamedMarkers.get(key);

                    if (marker == null) {
                        // This null-handling section should never be called in this listener's normal use, but is here to handle edge cases quietly.
                        Log.d(TAG, "Expected existing marker for '" + key + "', but one was not found. Added now.");
                        MarkerOptions options = getMarkerOptions(key); // TODO: Read data from database for this marker (e.g. Name, Driver, Vehicle type)
                        marker = mMap.addMarker(options.position(location));
                        mNamedMarkers.put(key, marker);
                    } else {
                        // TODO: Confirm if marker title/snippet needs updating.
                        marker.setPosition(location);
                    }
            }

            /**
             * Removes the marker from its GoogleMap instance
             * @param dataSnapshot  The removed data
             */
            @Override
            public void onChildRemoved(DataSnapshot dataSnapshot) {
                    String key = dataSnapshot.getKey();
                    Log.d(TAG, "Location for '" + key + "' was removed.");

                    Marker marker = mNamedMarkers.get(key);
                    if (marker != null)
                        marker.remove()
            }

            /**
             * Ignored.
             * @param dataSnapshot  The moved data
             * @param previousChildName  The key of the previous child event
             */
            @Override
            public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
                    // Unused
                    Log.d(TAG, "Priority for '" + dataSnapshot.getKey() "' was changed.");
            }

            /**
             * Error handler when listener is canceled.
             * @param databaseError  The error object
             */
            @Override
            public void onCancelled(DatabaseError databaseError) {
                    Log.w(TAG, "markerUpdateListener:onCancelled", databaseError.toException());
                    Toast.makeText(mContext, "Failed to load location markers.", Toast.LENGTH_SHORT).show();
            }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_map);
            // Obtain the SupportMapFragment and get notified when the map is ready to be used.
            SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                            .findFragmentById(R.id.map);
            mapFragment.getMapAsync(this);
    }

    /**
     * Waits for the map to be ready then loads markers from the database.
     * @param googleMap  The GoogleMap instance
     */
    @Override
    public void onMapReady(GoogleMap googleMap) {
            mMap = googleMap;

            database = FirebaseDatabase.getInstance();
            userLocationsRef = database.getReference("user");

            userLocationsRef.addChildEventListener(markerUpdateListener);



            // later when the activity becomes inactive.
            // userLocationsRef.removeEventListener(markerUpdateListener)
    }

    /**
     * Retrieves the marker data for the given key.
     * @param key  The ID of the marker
     * @return A MarkerOptions instance containing this marker's infoormation
     */
    private MarkerOptions getMarkerOptions(String key) {
        // TODO: Read data from database for the given marker (e.g. Name, Driver, Vehicle type)
        return new MarkerOptions().title('Location placeholder').snippet('Update this with marker information');
    } 
}
  • 每个标记都链接到数据库中名为
    mNamedMarkers
    的映射下的字符串ID
  • 由于没有提供
    模型
    ,而且似乎与此无关,因此我在下面的代码中省略了它
  • 我不确定你是否来自日耳曼背景,但在这里,
    lng
    是经度的缩写,而不是“lang”。我还想将您的数据库条目更改为使用
    lng
    而不是lang/long/longitude/etc(这样可以节省空间并消除混淆)
  • 在下面的代码中,我添加了
    getMarkerOptions(key)
    ,这样您就可以添加代码,根据每个标记的ID为其获取不同的图像、标题和文本。目前,它将为每个标记生成相同的数据
  • 我为每个函数添加了Javadoc标记,以总结每个函数的功能
  • 还有一些有待进一步开发的任务
代码如下:

public class Map extends FragmentActivity implements OnMapReadyCallback {
    FirebaseDatabase database;
    DatabaseReference userLocationsRef;
    GoogleMap mMap;

    Map<String, Marker> mNamedMarkers = new HashMap<String,Marker>();

    ChildEventListener markerUpdateListener = new ChildEventListener() {

            /**
             * Adds each existing/new location of a marker.
             *
             * Will silently update any existing markers as needed.
             * @param dataSnapshot  The new location data
             * @param previousChildName  The key of the previous child event
             */
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
                    String key = dataSnapshot.getKey();
                    Log.d(TAG, "Adding location for '" + key + "'");

                    Double lng = ds.child("lang").getValue(Double.class);
                    Double lat = ds.child("lat").getValue(Double.class);
                    LatLng location = new LatLng(lat, lng);

                    Marker marker = mNamedMarkers.get(key);

                    if (marker == null) {
                        MarkerOptions options = getMarkerOptions(key);
                        marker = mMap.addMarker(options.position(location));
                        mNamedMarkers.put(key, marker);
                    } else {
                        // This marker-already-exists section should never be called in this listener's normal use, but is here to handle edge cases quietly.
                        // TODO: Confirm if marker title/snippet needs updating.
                        marker.setPosition(location);
                    }
            }

            /**
             * Updates the location of a previously loaded marker.
             *
             * Will silently create any missing markers as needed.
             * @param dataSnapshot  The new location data
             * @param previousChildName  The key of the previous child event
             */
            @Override
            public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
                    String key = dataSnapshot.getKey();
                    Log.d(TAG, "Location for '" + key + "' was updated.");

                    Double lng = ds.child("lang").getValue(Double.class);
                    Double lat = ds.child("lat").getValue(Double.class);
                    LatLng location = new LatLng(lat, lng);

                    Marker marker = mNamedMarkers.get(key);

                    if (marker == null) {
                        // This null-handling section should never be called in this listener's normal use, but is here to handle edge cases quietly.
                        Log.d(TAG, "Expected existing marker for '" + key + "', but one was not found. Added now.");
                        MarkerOptions options = getMarkerOptions(key); // TODO: Read data from database for this marker (e.g. Name, Driver, Vehicle type)
                        marker = mMap.addMarker(options.position(location));
                        mNamedMarkers.put(key, marker);
                    } else {
                        // TODO: Confirm if marker title/snippet needs updating.
                        marker.setPosition(location);
                    }
            }

            /**
             * Removes the marker from its GoogleMap instance
             * @param dataSnapshot  The removed data
             */
            @Override
            public void onChildRemoved(DataSnapshot dataSnapshot) {
                    String key = dataSnapshot.getKey();
                    Log.d(TAG, "Location for '" + key + "' was removed.");

                    Marker marker = mNamedMarkers.get(key);
                    if (marker != null)
                        marker.remove()
            }

            /**
             * Ignored.
             * @param dataSnapshot  The moved data
             * @param previousChildName  The key of the previous child event
             */
            @Override
            public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
                    // Unused
                    Log.d(TAG, "Priority for '" + dataSnapshot.getKey() "' was changed.");
            }

            /**
             * Error handler when listener is canceled.
             * @param databaseError  The error object
             */
            @Override
            public void onCancelled(DatabaseError databaseError) {
                    Log.w(TAG, "markerUpdateListener:onCancelled", databaseError.toException());
                    Toast.makeText(mContext, "Failed to load location markers.", Toast.LENGTH_SHORT).show();
            }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_map);
            // Obtain the SupportMapFragment and get notified when the map is ready to be used.
            SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                            .findFragmentById(R.id.map);
            mapFragment.getMapAsync(this);
    }

    /**
     * Waits for the map to be ready then loads markers from the database.
     * @param googleMap  The GoogleMap instance
     */
    @Override
    public void onMapReady(GoogleMap googleMap) {
            mMap = googleMap;

            database = FirebaseDatabase.getInstance();
            userLocationsRef = database.getReference("user");

            userLocationsRef.addChildEventListener(markerUpdateListener);



            // later when the activity becomes inactive.
            // userLocationsRef.removeEventListener(markerUpdateListener)
    }

    /**
     * Retrieves the marker data for the given key.
     * @param key  The ID of the marker
     * @return A MarkerOptions instance containing this marker's infoormation
     */
    private MarkerOptions getMarkerOptions(String key) {
        // TODO: Read data from database for the given marker (e.g. Name, Driver, Vehicle type)
        return new MarkerOptions().title('Location placeholder').snippet('Update this with marker information');
    } 
}
公共类映射扩展了FragmentActivity在MapreadyCallback上的实现{
Firebase数据库;
数据库引用userLocationsRef;
谷歌地图;
Map mNamedMarkers=newhashmap();
ChildEventListener markerUpdateListener=新的ChildEventListener(){
/**
*添加标记的每个现有/新位置。
*
*将根据需要以静默方式更新任何现有标记。
*@param dataSnapshot新位置数据
*@param previousChildName上一个子事件的密钥
*/
@凌驾
公共void onChildAdded(DataSnapshot DataSnapshot,字符串previousChildName){
String key=dataSnapshot.getKey();
Log.d(标记“为“'+key+””添加位置);
Double lng=ds.child(“lang”).getValue(Double.class);
Double-lat=ds.child(“lat”).getValue(Double.class);
LatLng位置=新LatLng(lat,lng);
Marker=mNamedMarkers.get(键);
如果(标记==null){
MarkerOptions options=getMarkerOptions(键);
marker=mMap.addMarker(options.position(location));
mNamedMarkers.put(键、标记);
}否则{
//此标记已经存在,在侦听器的正常使用中不应调用该部分,但它用于安静地处理边缘情况。
//TODO:确认标记标题/代码段是否需要更新。
标记器。设置位置(位置);
}
}
/**
*更新以前加载的标记的位置。
*
*将根据需要以静默方式创建任何缺少的标记。
*@param dataSnapshot新位置数据
*@param previousChildName上一个子事件的密钥
*/
@凌驾
公共void onChildChanged(DataSnapshot DataSnapshot,字符串previousChildName){
String key=dataSnapshot.getKey();
Log.d(标记“'+key+'的位置已更新”);
Double lng=ds.child(“lang”).getValue(Double.class);
Double-lat=ds.child(“lat”).getValue(Double.class);
LatLng位置=新LatLng(lat,lng);
Marker=mNamedMarkers.get(键);
如果