Не могу ориентироваться в активности Google maps, она всегда возвращается в мое текущее местоположение

#java #android #google-maps-android-api-3

Вопрос:

Я новичок в разработке Android и работал над приложением, которое требует активности на карте Google. Проблема, с которой я сталкиваюсь, заключается в том, что при попытке панорамирования(или прокрутки) карты я немедленно возвращаюсь в свое текущее местоположение, которое я установил изначально. Небольшая помощь была бы замечательна, так как я застрял на этом этапе и не могу найти решение. Вот код:-

 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    binding = ActivityMapsBinding.inflate(getLayoutInflater());
    setContentView(binding.getRoot());

    // 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;
    mMap.getUiSettings().setScrollGesturesEnabled(true);
    locationManager=(LocationManager)this.getSystemService(Context.LOCATION_SERVICE);
    locationListener=new LocationListener() {
        @Override
        public void onLocationChanged(@NonNull Location location) {
            centerOnMap(location,"Your Location");
        }
    };

    if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)!= PackageManager.PERMISSION_GRANTED)
    {
        ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.ACCESS_FINE_LOCATION},1);
    }
    else{
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,0,0,locationListener);
        Location lastKnownLocation=locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
        centerOnMap(lastKnownLocation,"Your Location");
    }
}

public void centerOnMap(Location location,String address)
{
    LatLng userLocation = new LatLng(location.getLatitude(),location.getLongitude());
    mMap.addMarker(new MarkerOptions().position(userLocation).title(address));
    mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(userLocation, 15));
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull @org.jetbrains.annotations.NotNull String[] permissions, @NonNull @org.jetbrains.annotations.NotNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if(grantResults.length>0 amp;amp; grantResults[0]==PackageManager.PERMISSION_GRANTED)
    {
        if(ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION)==PackageManager.PERMISSION_GRANTED){
            locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,0,0,locationListener);
        }

    }
}
 

}

Комментарии:

1. Каждый раз, когда вы получаете обновление местоположения, камера перемещается в это местоположение ( centerOnMap вызывается в onLocationChanged ). Поэтому независимо от того, где вы прокрутили карту, она вернется в ваше местоположение при следующем обновлении. Если вам нужна дополнительная помощь, укажите, какое поведение вы бы предпочли вместо этого.

2. как говорит @Andy, за это отвечает ваша функция centerOnMap. более конкретно, при изменении вашего местоположения вызывается функция centerOnMap и строка mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(userLocation, 15)); измените положение карты на текущее местоположение. надеюсь, это вам поможет.

3. Спасибо @Andy за ответ, На самом деле я пытался сделать так, чтобы, когда пользователь открывает действие на карте, его/ее местоположение выбиралось, и маркер помещался в это место, и после этого пользователь мог перемещаться(прокручивать) карту и при длительном нажатии в определенной позиции маркер будет помещен туда(что я планировал сделать с помощью метода OnLongClickListener), поэтому, если вы можете указать, как обойти эту проблему прокрутки, это было бы полезно.

4. Спасибо @Abhra за ответ, пожалуйста, найдите комментарий выше и направьте меня, если сможете, по тому же поводу.

5. если вам не нужно обновлять местоположение пользователя, вы можете использовать FusedLocationProviderClient из com.google.android.gms:play-services-location вместо LocationManager.

Ответ №1:

Единственное требование, которое у вас, вероятно, есть, но не указано, — это:

Когда lastLocation карта станет доступной, а пользователь не переместил ее, затем центрируйте карту по местоположению. Если пользователь уже переместил карту, не центрируйте ее. В любом случае добавьте маркер в местоположение пользователя.

Прежде чем заходить слишком далеко, следует отметить, что Google Maps предоставляет функцию, аналогичную той, которую вы пытаетесь достичь, хотя вам все равно придется «переместить камеру». Маркер-это синий шар, а не типичный маркер. Видеть myMap.setMyLocationEnabled(true) . Вот и все! Сделайте это, когда у вас будут разрешения на карту.

Но в случае, если вы не хотите использовать это, вот простые изменения, которые вам нужны.

Помните, что LocationManager getLastKnownLocation может возвращать значение null, если на устройстве его нет (пока). Поэтому я бы рекомендовал одно небольшое изменение, немного не связанное с этим — просто позвольте слушателю местоположения выполнить всю работу и избавиться от этого одного особого случая:

 // this is where you initially check permissions and have them.
else{
    locationManager.requestLocationUpdates (LocationManager.GPS_PROVIDER,0,0,locationListener);
    // Here I removed the last location centering and let the
    // location listener always handle it.
}
 

Таким образом, это открывает возможность
того, что пользователь может взаимодействовать с картой, и, наконец, появляется последнее местоположение. Я понимаю, что это проблема, которую вы пытаетесь решить.

(В стороне, мне кажется, что вы смешиваете использование android.location.LocationManager с FusedLocationProviderApi (com.google.android.gms.location), поэтому я не смог скомпилировать ваш код из-за несовместимых LocationListener s. К сожалению, карты Google имеют два LocationListener класса, поэтому, чтобы быть уверенным, вам придется включить импорт, чтобы понять дальше.)

В любом случае…

Когда карта впервые готова ( onMapReady ), камера карты находится в центре (0,0) . Вы можете получить целевое положение камеры (в центре) в любое время с помощью LatLng tgtCtr = mMap.getCameraPosition().target; .

Как ни странно, узнать, взаимодействовал ли пользователь каким-либо образом с картой, непросто: события прокрутки генерируют изменения камеры, в то время как события касания генерируют отдельное событие. Изменения камеры нельзя использовать исключительно потому, что ваш код или пользователь могут просто увеличить масштаб, который не перемещает карту. Вы могли бы пойти по этому пути, но для целей этого ответа, чтобы все было просто, используется цель камеры.

Объявите переменную экземпляра класса (в той же области, где вы определяете mMap ):

 LatLng tgtCtr;
 

Так что в вашем onMapReady после назначения mMap сделайте:

 tgtCtr = mMap.getCameraPosition().target;
 

Поэтому предположим, что ваш код существует в том виде, в каком вы его опубликовали (он довольно близок), тогда эти
изменения могут помочь:

 // This change simply restricts centering of the map on location
// update to only when user has not moved the map (scrolled).

@Override
public void onLocationChanged(@NonNull Location location) {
    LatLng currentCtr = mMap.getCamaraPosition().target;
    
    // This is not the ideal check since `double` comparisons 
    // should account for epsilon but in this case of (0,0) it should work.
    
    // Alternatively you could compute the distance of current
    // center to (0,0) and then use an epsilon: 
    //    see `com.google.maps.android.SphericalUtil.computeDistanceBetween`.
    
    if (currentCtr.latitude == 0 amp;amp; currentCtr.longitude == 0) {
        centerOnMap(location,"Your Location");
    }
}
 

Также кажется хорошей идеей сохранить маркер, который был добавлен для
местоположения пользователя — это необязательно, но может пригодиться, чтобы предотвратить добавление нескольких маркеров
в одном месте:

 // Define a class instance variable
Marker myLocMarker = nulll;

// and then in centerOnMap
public void centerOnMap(Location location, String address)
{
    // ... other code

    if (myLocMarker == null) {
        myLocMarker = mMap.addMarker(new MarkerOptions().position(userLocation).title(address));
    }

    // ... more code
}
 

Так что на самом деле единственная трудность в этом-выяснить, »
переместил ли пользователь карту». В этом случае, исходя из первоначального требования
, вы не захотите перемещать карту.

Ответ №2:

как вы упомянули в разделе комментариев, используйте FusedLocationProviderClient вместо LocationManager. добавьте implementation 'com.google.android.gms:play-services-location:17.0.0' в приложение градуировку уровня. и не забудьте добавить разрешение на манифест для точного определения местоположения.

 public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {

private GoogleMap mMap;

FusedLocationProviderClient mFusedLocationClient;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_maps);
    SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
            .findFragmentById(R.id.map);
    mapFragment.getMapAsync(this);
    mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);

}

@Override
public void onMapReady(GoogleMap googleMap) {
    mMap = googleMap;
    mMap.getUiSettings().setScrollGesturesEnabled(true);

    getLastLocation();
    mMap.setOnMapLongClickListener(new GoogleMap.OnMapLongClickListener() {
        @Override
        public void onMapLongClick(@NonNull LatLng latLng) {

            Location location = new Location(LocationManager.GPS_PROVIDER);
            location.setLatitude(latLng.latitude);
            location.setLongitude(latLng.longitude);
            centerOnMap(location,"Your location");
        }
    });
}


@SuppressLint("MissingPermission")
private void getLastLocation() {
    if (checkPermissions()) {
        if (isLocationEnabled()) {
            mFusedLocationClient.getLastLocation().addOnCompleteListener(new OnCompleteListener<Location>() {
                @Override
                public void onComplete(@NonNull Task<Location> task) {
                    Location location = task.getResult();
                    if (location == null) {
                        requestNewLocationData();
                    } else {
                        centerOnMap(location,"Your Location");
                    }
                }
            });
        } else {
            Toast.makeText(this, "Please turn on"   " your location...", Toast.LENGTH_LONG).show();
            Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
            startActivity(intent);
        }
    } else {
        requestPermissions();
    }
}

@SuppressLint("MissingPermission")
private void requestNewLocationData() {
    LocationRequest mLocationRequest = new LocationRequest();
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    mLocationRequest.setInterval(5);
    mLocationRequest.setFastestInterval(0);
    mLocationRequest.setNumUpdates(1);
    mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
    mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
}

private LocationCallback mLocationCallback = new LocationCallback() {

    @Override
    public void onLocationResult(LocationResult locationResult) {
        Location mLastLocation = locationResult.getLastLocation();
        centerOnMap(mLastLocation,"Your Location");
    }
};

private boolean checkPermissions() {
    return ActivityCompat.checkSelfPermission(this,   Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
}

private void requestPermissions() {
    ActivityCompat.requestPermissions(this, new String[]{
            Manifest.permission.ACCESS_FINE_LOCATION}, 1);
}

private boolean isLocationEnabled() {
    LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
}

public void centerOnMap(Location location,String address)
{
    LatLng userLocation = new LatLng(location.getLatitude(),location.getLongitude());
    mMap.clear();
    mMap.addMarker(new MarkerOptions().position(userLocation).title(address));
    mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(userLocation, 15));
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if(grantResults.length>0 amp;amp; grantResults[0]==PackageManager.PERMISSION_GRANTED)
    {
        getLastLocation();
    }
}
 

}