5
  package com.jaygandhi.map3;

 import android.Manifest;
 import android.content.pm.PackageManager;
 import android.location.Location;
 import android.os.Build;
 import android.support.v4.app.ActivityCompat;
 import android.support.v4.app.FragmentActivity;
 import android.os.Bundle;
 import android.support.v4.content.ContextCompat;
 import android.support.v7.app.AppCompatActivity;
 import android.widget.Toast;

 import com.google.android.gms.common.ConnectionResult;
 import com.google.android.gms.common.api.GoogleApiClient;
 import com.google.android.gms.location.LocationListener;
 import com.google.android.gms.location.LocationRequest;
 import com.google.android.gms.location.LocationServices;
 import com.google.android.gms.maps.CameraUpdateFactory;
 import com.google.android.gms.maps.GoogleMap;
 import com.google.android.gms.maps.OnMapReadyCallback;
 import com.google.android.gms.maps.SupportMapFragment;
 import com.google.android.gms.maps.model.BitmapDescriptorFactory;
 import com.google.android.gms.maps.model.LatLng;
 import com.google.android.gms.maps.model.Marker;
 import com.google.android.gms.maps.model.MarkerOptions;



public class MapsActivity extends AppCompatActivity
        implements OnMapReadyCallback,
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener,
        LocationListener
{

    GoogleMap mGoogleMap;
    SupportMapFragment mapFrag;
    LocationRequest mLocationRequest;
    GoogleApiClient mGoogleApiClient;
    Location mLastLocation;
    Marker mCurrLocationMarker;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_maps);

        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            checkLocationPermission();
        }

        mapFrag = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
        mapFrag.getMapAsync(this);
    }

    @Override
    public void onPause() {
        super.onPause();

        //stop location updates when Activity is no longer active
        if (mGoogleApiClient != null) {
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
        }
    }

    @Override
    public void onMapReady(GoogleMap googleMap)
    {
        mGoogleMap=googleMap;
        mGoogleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);

        //Initialize Google Play Services
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (ContextCompat.checkSelfPermission(this,
                    Manifest.permission.ACCESS_FINE_LOCATION)
                    == PackageManager.PERMISSION_GRANTED) {
                buildGoogleApiClient();
                mGoogleMap.setMyLocationEnabled(true);
            }
        }
        else {
            buildGoogleApiClient();
            mGoogleMap.setMyLocationEnabled(true);
        }
    }

    protected synchronized void buildGoogleApiClient() {
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
        mGoogleApiClient.connect();
    }

    @Override
    public void onConnected(Bundle bundle)
    {
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(1000);
        mLocationRequest.setFastestInterval(1000);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_FINE_LOCATION)
                == PackageManager.PERMISSION_GRANTED)
        {

            LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);

        }
    }

    @Override
    public void onConnectionSuspended(int i) {}

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {}

    @Override
    public void onLocationChanged(Location location)
    {
        mLastLocation = location;
        if (mCurrLocationMarker != null)
        {
            mCurrLocationMarker.remove();
        }

        //Place current location marker
        LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
        MarkerOptions markerOptions = new MarkerOptions();
        markerOptions.position(latLng);
        markerOptions.title("Current Position");
        markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ORANGE));
        mCurrLocationMarker = mGoogleMap.addMarker(markerOptions);

        //move map camera
        mGoogleMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
        mGoogleMap.animateCamera(CameraUpdateFactory.zoomTo(11));

        if (mGoogleApiClient != null)
        {
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
        }
    }

    public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;
    public boolean checkLocationPermission(){
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {

            // Should we show an explanation?
            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.ACCESS_FINE_LOCATION)) {

                // Show an expanation to the user *asynchronously* -- don't block
                // this thread waiting for the user's response! After the user
                // sees the explanation, try again to request the permission.

                //Prompt the user once explanation has been shown
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                        MY_PERMISSIONS_REQUEST_LOCATION);


            } else {
                // No explanation needed, we can request the permission.
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                        MY_PERMISSIONS_REQUEST_LOCATION);
            }
            return false;
        } else {
            return true;
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           String permissions[], int[] grantResults) {
        switch (requestCode) {
            case MY_PERMISSIONS_REQUEST_LOCATION: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                    // permission was granted, yay! Do the
                    // contacts-related task you need to do.
                    if (ContextCompat.checkSelfPermission(this,
                            Manifest.permission.ACCESS_FINE_LOCATION)
                            == PackageManager.PERMISSION_GRANTED) {

                        if (mGoogleApiClient == null) {
                            buildGoogleApiClient();
                        }
                        mGoogleMap.setMyLocationEnabled(true);
                    }

                } else {

                    // permission denied, boo! Disable the
                    // functionality that depends on this permission.
                    Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show();
                }
                return;
            }

            // other 'case' lines to check for other
            // permissions this app might request
        }
    }

}

This code I get from different answer but it did not update in real time.

I tried this code but when maps loads first time marker show current location but when my location is changed marker do not move to new location.

Daniel Nugent
  • 43,104
  • 15
  • 109
  • 137
jay gandhi
  • 61
  • 1
  • 2
  • 5

5 Answers5

6

You just need to remove the call to removeLocationUpdates() in onLocationChanged():

@Override
public void onLocationChanged(Location location)
{
    mLastLocation = location;
    if (mCurrLocationMarker != null)
    {
        mCurrLocationMarker.remove();
    }

    //Place current location marker
    LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
    MarkerOptions markerOptions = new MarkerOptions();
    markerOptions.position(latLng);
    markerOptions.title("Current Position");
    markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ORANGE));
    mCurrLocationMarker = mGoogleMap.addMarker(markerOptions);

    //move map camera
    mGoogleMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
    mGoogleMap.animateCamera(CameraUpdateFactory.zoomTo(11));

    //Remove this code:
    //if (mGoogleApiClient != null)
    //{
      //LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
    //}
}

Also add an onResume() Override and re-register for location updates if the Google API Client is not null:

@Override
public void onResume() {
    super.onResume();
    if (mGoogleApiClient != null &&
            ContextCompat.checkSelfPermission(this,
            Manifest.permission.ACCESS_FINE_LOCATION)
            == PackageManager.PERMISSION_GRANTED) {
        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
    }
}

The original code was designed to only get one location, and then remove location updates after the first location comes in.

Bear in mind that keeping a location listener active for long periods will cause more battery drain.

Also note that for testing purposes, you can set more aggressive values in the location request:

@Override
public void onConnected(Bundle bundle)
{
    mLocationRequest = new LocationRequest();
    mLocationRequest.setInterval(1000);
    mLocationRequest.setFastestInterval(1000);
    mLocationRequest.setSmallestDisplacement(0.1F); //added
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); //changed
    if (ContextCompat.checkSelfPermission(this,
            Manifest.permission.ACCESS_FINE_LOCATION)
            == PackageManager.PERMISSION_GRANTED)
    {

        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);

    }
}

Making the above changes, this code works for me:

public class MapLocationActivity extends AppCompatActivity
        implements OnMapReadyCallback,
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener,
        LocationListener {

    GoogleMap mGoogleMap;
    SupportMapFragment mapFrag;
    LocationRequest mLocationRequest;
    GoogleApiClient mGoogleApiClient;
    Location mLastLocation;
    Marker mCurrLocationMarker;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            checkLocationPermission();
        }

        mapFrag = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
        mapFrag.getMapAsync(this);
    }

    @Override
    public void onPause() {
        super.onPause();

        //stop location updates when Activity is no longer active
        if (mGoogleApiClient != null) {
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        if (mGoogleApiClient != null &&
                ContextCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_FINE_LOCATION)
                == PackageManager.PERMISSION_GRANTED) {
            LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
        }
    }

    @Override
    public void onMapReady(GoogleMap googleMap)
    {
        mGoogleMap=googleMap;
        mGoogleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);

        //Initialize Google Play Services
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (ContextCompat.checkSelfPermission(this,
                    Manifest.permission.ACCESS_FINE_LOCATION)
                    == PackageManager.PERMISSION_GRANTED) {
                buildGoogleApiClient();
                mGoogleMap.setMyLocationEnabled(true);
            }
        }
        else {
            buildGoogleApiClient();
            mGoogleMap.setMyLocationEnabled(true);
        }
    }

    protected synchronized void buildGoogleApiClient() {
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
        mGoogleApiClient.connect();
    }

    @Override
    public void onConnected(Bundle bundle) {
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(1000);
        mLocationRequest.setFastestInterval(1000);
        mLocationRequest.setSmallestDisplacement(0.1f);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_FINE_LOCATION)
                == PackageManager.PERMISSION_GRANTED) {
            LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
        }
    }

    @Override
    public void onConnectionSuspended(int i) {}

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {}

    @Override
    public void onLocationChanged(Location location)
    {
        Toast.makeText(this, "Location Changed " + location.getLatitude()
                + location.getLongitude(), Toast.LENGTH_LONG).show();

        mLastLocation = location;
        if (mCurrLocationMarker != null) {
            mCurrLocationMarker.remove();
        }

        //Place current location marker
        LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
        MarkerOptions markerOptions = new MarkerOptions();
        markerOptions.position(latLng);
        markerOptions.title("Current Position");
        markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));
        mCurrLocationMarker = mGoogleMap.addMarker(markerOptions);

        //move map camera
        mGoogleMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
        mGoogleMap.animateCamera(CameraUpdateFactory.zoomTo(11));


    }

    public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;
    public boolean checkLocationPermission(){
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {

            // Should we show an explanation?
            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.ACCESS_FINE_LOCATION)) {

                // Show an expanation to the user *asynchronously* -- don't block
                // this thread waiting for the user's response! After the user
                // sees the explanation, try again to request the permission.

                //Prompt the user once explanation has been shown
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                        MY_PERMISSIONS_REQUEST_LOCATION);


            } else {
                // No explanation needed, we can request the permission.
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                        MY_PERMISSIONS_REQUEST_LOCATION);
            }
            return false;
        } else {
            return true;
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           String permissions[], int[] grantResults) {
        switch (requestCode) {
            case MY_PERMISSIONS_REQUEST_LOCATION: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                    // permission was granted, yay! Do the
                    // contacts-related task you need to do.
                    if (ContextCompat.checkSelfPermission(this,
                            Manifest.permission.ACCESS_FINE_LOCATION)
                            == PackageManager.PERMISSION_GRANTED) {

                        if (mGoogleApiClient == null) {
                            buildGoogleApiClient();
                        }
                        mGoogleMap.setMyLocationEnabled(true);
                    }

                } else {

                    // permission denied, boo! Disable the
                    // functionality that depends on this permission.
                    Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show();
                }
                return;
            }

            // other 'case' lines to check for other
            // permissions this app might request
        }
    }

}
Daniel Nugent
  • 43,104
  • 15
  • 109
  • 137
  • sir, i removed this lines you told me and i went outside and check it again... but still marker is not moving to new location – jay gandhi Apr 16 '16 at 16:40
  • google's default current location marker(blue dot) is moving to new location , but costume marker markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ORANGE)); is not moving to new location – jay gandhi Apr 16 '16 at 16:55
  • yes, i can send you screenshot, i am trying this from 2 days – jay gandhi Apr 16 '16 at 17:03
  • it works only first time , when we load the map , after that when we change location costume marker is not moving as default google marker moves. – jay gandhi Apr 16 '16 at 17:32
  • @jaygandhi I just updated the answer again, I realized that it needs to re-register for location updates in onResume() in order for it to work correctly when opening the app when it was already running in the background. – Daniel Nugent Apr 16 '16 at 18:48
  • thank you very much sir , it is working now, but can help me in fixing zoom level and camera potion for current location? i am using fake gps app to test the code, when i make change latitude and longitude in fake gps and again open the above code , it reloads the map and zoom to default level... how to maintain zoom level and camera position for current location – jay gandhi Apr 17 '16 at 05:15
  • @jay glad it's working! As for your next question, that is a bit broad, but basically you need to figure out all of the cases that you do want to set the zoom level, and when you want to leave it alone, and then write support for all of those cases in the code. – Daniel Nugent Apr 17 '16 at 05:39
  • in this code onStart() method is needed or not ? because when i open application it takes 5-10 to detect the location. any solution for that ? I am making live gps tracking application for my final year project. – jay gandhi Apr 17 '16 at 05:46
  • No, onStart() is not needed. I tested this code on a real device, and it got a location immediately every time, but it may have to do with my location (lots of wifi hotspots around) – Daniel Nugent Apr 17 '16 at 05:49
  • Or i put make changes in onMapReady() ready method ? can you help me also in geofancing ? – jay gandhi Apr 17 '16 at 05:52
  • How to send notification to one user when another user is in the first's user's Geofencing region – jay gandhi Apr 17 '16 at 05:59
  • Sir How do i zoom in automatically to the current location in this code – jay gandhi Apr 17 '16 at 10:41
  • @DanielNugent what if there are more than one marker? – Hammad Nasir Feb 23 '17 at 18:57
  • 1
    @HammadNasir This example only uses one Marker to show your current location. Of course, you can add as many Markers as you like in addition to the current location Marker. – Daniel Nugent Feb 23 '17 at 19:18
  • @DanielNugent thanks for replying. In my case, several players opens this activity which has a map from their devices and their location is shown on the map. Now what I want is to update the respective marker whenever any user's location changes to the respective location. How can I achieve this? Please guide me through this. – Hammad Nasir Feb 23 '17 at 19:23
  • @HammadNasir Are you trying to show all online user's location to each user of the app? – Daniel Nugent Feb 23 '17 at 19:25
  • @DanielNugent yeah sort of... Not to each user of the app but to a particular group of users. Each others location to each other users (online users) in that group. – Hammad Nasir Feb 23 '17 at 19:27
  • 1
    @HammadNasir Well, you'll need to develop server functionality such that each user can tell the server their location, and also query the server to get the location of other users in their group. Then, for each location the server gives you for other users, place a Marker on the map. – Daniel Nugent Feb 23 '17 at 19:32
  • @DanielNugent Yeah... I've tried it but still having issues. It'd be really helpful if you can help with this: http://stackoverflow.com/q/42252017/6144372 – Hammad Nasir Feb 23 '17 at 19:36
  • @DanielNugent hey... Please help with it. Thanks. – Hammad Nasir Feb 24 '17 at 00:50
1

Here is a Simple method of updating marker as soon as the location changes! As we know the onLocationChanged() methode is called when ever there is a change in location. And here we basically set the marker to the current position. Follow the process given bellow. That works for me and I hope it will do for you as well :)

@RequiresApi(api = Build.VERSION_CODES.N)//This line requires if you are using 25/26 API
@Override
public void onLocationChanged(Location location) {
    //Removing previously added markers here!
    mMap.clear();
    Log.d(TAG, "Firing onLocationChanged..............................................");
    mCurrentLocation = location;
    mLastUpdateTime = DateFormat.getTimeInstance().format(new Date());

    updateUI();
}

We can simply clear previously added markers using the mMap.clear() where mMap is the GoogleMap object and is also called and assigned in onMapReady() methode. Then we can get current location and set marker in an external method which is here: updateUI();

private void updateUI() {
    Log.d(TAG, "UI update initiated .............");
    if (null != mCurrentLocation) {

        LatLng allLatLang = new LatLng(mCurrentLocation.getLatitude(),mCurrentLocation.getLongitude());

        MarkerOptions markerOptions = new MarkerOptions();
        markerOptions.position(allLatLang);
        markerOptions.title("USER NAME");
        markerOptions.snippet("Users Basic Information");
        markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ORANGE));
        locationMarker = mMap.addMarker(markerOptions);

        //You can add this lines if you want to show the realtime data change on any TextView
        String lat = String.valueOf(mCurrentLocation.getLatitude());
        String lng = String.valueOf(mCurrentLocation.getLongitude());
        locationUpdate.setText("At Time: " + mLastUpdateTime + "\n" +
                "Latitude: " + lat + "\n" +
                "Longitude: " + lng + "\n" +
                "Accuracy: " + mCurrentLocation.getAccuracy() + "\n" +
                "Provider: " + mCurrentLocation.getProvider());
    } else {
        Log.d(TAG, "location is null ...............");
    }
}

So, when ever the location is changing, the onLocationChanged() method is called and then we are removing the existing markers and setting it again to the new position. Hope this will work out. Let me know if it helps. Thank you.!

Tamim
  • 181
  • 1
  • 12
0

Implement OnCameraMoveListener and set new position for existing marker in onCameraMove

@Override
public void onCameraMove() {

    mMarker.setPosition(mMap.getCameraPosition().target);

}
kalpeshdeo
  • 1,236
  • 1
  • 11
  • 16
0

Inside your onLocationChanged try like this

        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(currentLocationLatLng, 18));
        if(myMarker == null) {
            myMarker = mMap.addMarker(new MarkerOptions().position(currentLocationLatLng)
                    .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN)));
        } else {
            myMarker.setPosition(currentLocationLatLng);
        }

This is the better way to move existing marker then clear and create it again.

Jahangir Kabir
  • 1,783
  • 13
  • 17
0

call it in on map ready

public void getLocation(){
    new FusedLocationProviderClient(this).getLastLocation()
            .addOnCompleteListener(task -> {
                Location location = task.getResult();
                if(location!=null&&mMap!=null){
                    mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(
                        new LatLng(location.getLatitude(),location.getLongitude()),15
                    ));
                    mMap.setMyLocationEnabled(true);
                    new Handler().postDelayed(this::getLocation,5000);
                }
            });
}
kyun
  • 9,710
  • 9
  • 31
  • 66