Iv'e been trying to implement an activity that has a map and can use a button to focus and put a marker on your current location. the problem is most of the time i get a really slow (if any) location data, and while iv'e seen apps do the same in 1-2 seconds, mine takes 20 secs at least to get data if it even gets data. how do i speed it up? what am i doing wrong? (if it helps i think i might have used extra unnecessary functions and implemented extra stuff including importing extra stuff the is unnedeed):
here's my code:
MapsActivity.java
import android.Manifest;
import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationManager;
import android.os.Build;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.Toolbar;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
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.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import org.w3c.dom.Text;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
/**
* AppCompatActivity extends FragmentActivity and allows me to have a menu over the map!
*/
public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback, ActivityCompat.OnRequestPermissionsResultCallback {
/**
* THE Map is a FRAGMENT! i must treat it as such and therefore i need something to hold this
* fragment, another activity will be the Main activity and will hold the map's fragment!
*/
private GoogleMap mMap;
Marker marker; // i use this so i can erase it later.
private static final int REQUEST_PERMISSION_CODE = 1;
/**
* This array is holding int values for the many different map types googleMaps
* offers. the mapType value is now set to 1 for normal and can be changed in an instance.
*/
private final int[] mapTypes = {GoogleMap.MAP_TYPE_NONE, GoogleMap.MAP_TYPE_NORMAL
, GoogleMap.MAP_TYPE_TERRAIN, GoogleMap.MAP_TYPE_SATELLITE, GoogleMap.MAP_TYPE_HYBRID};
private int mapType = 1;
public static final String TAG = MapsActivity.class.getSimpleName();
private Button mGpsLocateButton;
private Button mAddressLocateButton;
private TextView mAddressTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// 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);
ActionBar actionBar = getSupportActionBar();
actionBar.setTitle(R.string.app_name);
/**
* Setting up a location manager to get location feed from gps or data.
*/
//mLocationManager = (LocationManager)getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
final LocationFinder mLocationFinder = LocationFinder.getLocationFinder(this);
/**
* This is the TextView that shows the local area and street, next up we find the location
* by string and set the view to show it! we set it on start to show the address of
* the Central Station in beer sheva. later it will show local address.
*/
mAddressTextView = (TextView) findViewById(R.id.street_text_view);
Geocoder geocoder = new Geocoder(this, Locale.getDefault());
LatLng centralStationBS = new LatLng(31.243077, 34.796961);
String address = findAddress(centralStationBS,geocoder);
mAddressTextView.setText(address);
mGpsLocateButton = (Button) findViewById(R.id.gps_locate_button);
mGpsLocateButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mLocationFinder.startLocationListening();
Location loc = mLocationFinder.getBestKnownLocation();
/**
* the counter will allow the program to try to acquire position
*/
int count = 0;
while (loc == null && count < 10) {
synchronized (this) {
try {
this.wait(500);
count++;
loc = mLocationFinder.getBestKnownLocation();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* if we still got no location we prompt the user to try turning GPS on.
* will change later!!!
*/
if (loc == null) {
int noLocation = R.string.cannot_get_location_toast;
Toast.makeText(getApplicationContext(), noLocation, Toast.LENGTH_SHORT).show();
mAddressTextView.setText("No address found, Turn GPS on.");
}
if (loc != null) {
//marker.remove();
LatLng currentLoc = new LatLng(loc.getLatitude(), loc.getLongitude());
//marker = mMap.addMarker(new MarkerOptions().position(currentLoc).title("You Are Here!").draggable(true));
marker.setPosition(currentLoc);
marker.setTitle("You Are Here!");
marker.setDraggable(true);
mMap.moveCamera(CameraUpdateFactory.newLatLng(currentLoc));
mMap.moveCamera(CameraUpdateFactory.zoomTo(17));
Geocoder geocoder = new Geocoder(getApplicationContext(),Locale.getDefault());
String address = findAddress(currentLoc,geocoder);
mAddressTextView.setText(address);
}
}
});
mAddressLocateButton = (Button) findViewById(R.id.address_locate_button);
mAddressLocateButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
}
/**
* Manipulates the map once available.
* This callback is triggered when the map is ready to be used.
* This is where we can add markers or lines, add listeners or move the camera. In this case,
* we just add a marker near Sydney, Australia.
* If Google Play services is not installed on the device, the user will be prompted to install
* it inside the SupportMapFragment. This method will only be triggered once the user has
* installed Google Play services and returned to the app.
*/
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.getUiSettings().setMapToolbarEnabled(false);
// Add a marker in weWork and move the camera
LatLng weWork = new LatLng(31.264089, 34.812974);
LatLng centralStationBS = new LatLng(31.243077, 34.796961);
//i set the marker to draggable, might not be necessery.
marker = mMap.addMarker(new MarkerOptions().position(centralStationBS).title("BS Central Station").draggable(true));
mMap.moveCamera(CameraUpdateFactory.newLatLng(centralStationBS));
mMap.moveCamera(CameraUpdateFactory.zoomTo(17));
/**
* This should check if we have permission and if not it will ask from the user.
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_PERMISSION_CODE);
}*/
}
/**
* overriding on resume since we might disconnect and the client needs
* to be connected again.
* Reminder:
* Activity LifeCycle: onResume() comes directly after onCreate() so we
* connect on the beginning.
*/
@Override
public void onResume() {
super.onResume();
}
/**
* overriding on pause since we might want to disconnect when pausing the app.
*/
@Override
public void onPause() {
super.onPause();
}
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
/** if(requestCode == REQUEST_PERMISSION_CODE){
if(grantResults.length>0) {
loc.setPermissionGranted(grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1]== PackageManager.PERMISSION_GRANTED);
}
}*/
}
public String findAddress(LatLng location, Geocoder geocoder) {
String address;
try {
List<Address> addressList = geocoder.getFromLocation(location.latitude, location.longitude, 1); //the 1 stands for max results.
if (addressList != null) {
Address returnedAddress = addressList.get(0);
StringBuilder returnedAddressAsString = new StringBuilder();
for (int i = 0; i < returnedAddress.getMaxAddressLineIndex(); i++) {
returnedAddressAsString.append(returnedAddress.getAddressLine(i)).append("");
}
address = returnedAddressAsString.toString();
} else {
address = "No address found";
}
} catch (IOException e) {
e.printStackTrace();
address = "No address found";
}
return address;
}
}
LocationFinder.java:
import android.annotation.TargetApi;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;
/**
* Here we will use the methods shown in https://developer.android.com/guide/topics/location/strategies.html
* there is a different, maybe easier approach to it in https://developer.android.com/training/location/index.html
* GIANT NOTE TO SELF: THIS METHOD IS NOT SO ACCURATE, I NEED TO ENHANCE ACCURACY OR CHANGE METHOD TO WHATEVER
* GOOGLE API MEANT!(the easier method).
* Created by Snirkd on 6/16/2016.
*/
public class LocationFinder {
private static LocationFinder mLocationFinder;
private LocationManager mLocationManager;
private Context mAppContext;
private static final int TEN_SECS = 1000 * 10;
private LocationListener mLocationListener;
private Location lastKnownGPSLocation;
private Location lastKnownNetworkLocation;
private Location bestKnownLocation;
private boolean hasNewLocation = false;
private boolean isGPSon;
private boolean isNetworkOn;
private boolean requestedUpdates = false;
private LocationFinder(Context appContext) {
mAppContext = appContext;
//acquire a reference to the system location manager
mLocationManager = (LocationManager) mAppContext.getSystemService(Context.LOCATION_SERVICE);
initService();
}
public static LocationFinder getLocationFinder(Context context) {
if (mLocationFinder == null)
mLocationFinder = new LocationFinder(context);
return mLocationFinder;
}
private void initService() {
//define a listener that responds to location updates
mLocationListener = new LocationListener() {
// Called when a new location is found by the network location provider
@Override
public void onLocationChanged(Location location) {
if (Build.VERSION.SDK_INT >= 23 &&
ContextCompat.checkSelfPermission(mAppContext, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
Log.d("LOCATION FINDER","I AM HERERERERE6");
String provider = location.getProvider();
if(provider.equals(LocationManager.GPS_PROVIDER)){
if(isBetterLocation(location,lastKnownGPSLocation))
lastKnownGPSLocation = location;
}
if(provider.equals(LocationManager.NETWORK_PROVIDER)){
if(isBetterLocation(location,lastKnownNetworkLocation))
lastKnownNetworkLocation = location;
}
boolean isLastbetter = isBetterLocation(lastKnownGPSLocation,lastKnownNetworkLocation);
if(isLastbetter){
boolean betterThanBestKnownLocation = isBetterLocation(lastKnownGPSLocation,bestKnownLocation);
if(betterThanBestKnownLocation){
bestKnownLocation = lastKnownGPSLocation;
}
}else{
boolean betterThanBestKnownLocation = isBetterLocation(lastKnownNetworkLocation,bestKnownLocation);
if(betterThanBestKnownLocation){
bestKnownLocation = lastKnownNetworkLocation;
}
}
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
if(provider.equals(LocationManager.GPS_PROVIDER)) {
isGPSon = true;
}else{
isNetworkOn = true;
}
}
@Override
public void onProviderDisabled(String provider) {
if(provider.equals(LocationManager.GPS_PROVIDER)) {
isGPSon = false;
}else{
isNetworkOn = false;
}
if(!isGPSon && !isNetworkOn){
stopListening();
}
}
};
/**
* Register the listener with the location manager to receive location updates
* The first parameter in requestLocationUpdates() is the type of location provider
* to use (in this case, the Network Location Provider for cell tower and Wi-Fi based location).
* You can control the frequency at which your listener receives updates with the second
* and third parameter—the second is the minimum time interval between notifications
* and the third is the minimum change in distance between notifications—setting both
* to zero requests location notifications as frequently as possible. The last parameter
* is your LocationListener, which receives callbacks for location updates.
* To request location updates from the GPS provider, substitute GPS_PROVIDER for NETWORK_PROVIDER.
* You can also request location updates from both the GPS and the Network Location Provider by
* calling requestLocationUpdates() twice—once for NETWORK_PROVIDER and once for GPS_PROVIDER.
*/
}
/**
* Determines whether one Location reading is better than the current Location fix
*
* @param location The new Location that you want to evaluate
* @param currentBestLocation The current Location fix, to which you want to compare the new one
*/
protected boolean isBetterLocation(Location location, Location currentBestLocation) {
if (currentBestLocation == null) {
// A new location is always better than no location
return true;
} else if(location == null){
return false;
}
// Check whether the new location fix is newer or older
long timeDelta = location.getTime() - currentBestLocation.getTime();
boolean isSignificantlyNewer = timeDelta > TEN_SECS;
boolean isSignificantlyOlder = timeDelta < -TEN_SECS;
boolean isNewer = timeDelta > 0;
// If it's been more than two minutes since the current location, use the new location
// because the user has likely moved
if (isSignificantlyNewer) {
return true;
// If the new location is more than two minutes older, it must be worse
} else if (isSignificantlyOlder) {
return false;
}
// Check whether the new location fix is more or less accurate
int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
boolean isLessAccurate = accuracyDelta > 0;
boolean isMoreAccurate = accuracyDelta < 0;
boolean isSignificantlyLessAccurate = accuracyDelta > 200;
// Check if the old and new location are from the same provider
boolean isFromSameProvider = isSameProvider(location.getProvider(),
currentBestLocation.getProvider());
// Determine location quality using a combination of timeliness and accuracy
if (isMoreAccurate) {
return true;
} else if (isNewer && !isLessAccurate) {
return true;
} else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
return true;
}
return false;
}
/**
* Checks whether two providers are the same
*/
private boolean isSameProvider(String provider1, String provider2) {
if (provider1 == null) {
return provider2 == null;
}
return provider1.equals(provider2);
}
@TargetApi(23)
public void startLocationListening(){
if(requestedUpdates == true)
return;
if (Build.VERSION.SDK_INT >= 23 &&
ContextCompat.checkSelfPermission(mAppContext, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 10 , mLocationListener);
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 10, mLocationListener);
requestedUpdates = true;
Log.d("LOCATION FINDER", "I AM HERERERERE1");
lastKnownNetworkLocation = mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
lastKnownGPSLocation = mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
Log.d("LOCATION FINDER","I AM HERERERERE2");
/**
* check which is better and assign a new location with it. if non exist
* then we have no new location as of now and will note it.
*/
boolean betterLocation = isBetterLocation(lastKnownGPSLocation,lastKnownNetworkLocation);
if(betterLocation && lastKnownGPSLocation!=null){
bestKnownLocation = lastKnownGPSLocation;
hasNewLocation = true;
Log.d("LOCATION FINDER","I AM HERERERERE3");
}else if(!betterLocation && lastKnownNetworkLocation!=null){
bestKnownLocation = lastKnownNetworkLocation;
hasNewLocation = true;
Log.d("LOCATION FINDER","I AM HERERERERE4");
}
else hasNewLocation = false;
Log.d("LOCATION FINDER","I AM HERERERERE5");
}
@TargetApi(23)
public void stopListening(){
if (Build.VERSION.SDK_INT >= 23 &&
ContextCompat.checkSelfPermission(mAppContext, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
mLocationManager.removeUpdates(mLocationListener);
requestedUpdates = false;
}
public boolean hasNewLocation(){
return hasNewLocation;
}
public Location getBestKnownLocation(){
return bestKnownLocation;
}
public boolean isProviderEnabled(String provider){
return mLocationManager.isProviderEnabled(provider);
}
}