我一直在尝试实施一个包含地图的活动,并且可以使用按钮来聚焦并在当前位置放置标记。问题是大多数时候我得到一个非常慢的(如果有的话)位置数据,虽然我看到应用程序在1-2秒内做同样的事情,但如果它甚至获取数据,我至少需要20秒来获取数据。 我该如何加快速度?我究竟做错了什么? (如果它有帮助我认为我可能已经使用了额外的不必要的功能并实现了额外的东西,包括导入额外的东西,这是不必要的):
这是我的代码:
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);
}
}
答案 0 :(得分:0)
根据我的理解,您可以在打开MapActivity时在地图中显示当前位置。为此,您可以执行以下操作
public class MapActivity extends AppCompatActivity
implements OnMapReadyCallback {
private static final int CONNECTION_FAILURE_RESOLUTION_REQUEST = 1;
public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;
private GoogleMap mGoogleMap;
private GoogleApiClient mGoogleApiClient;
private SupportMapFragment mapFragment;
private LocationRequest mLocationRequest;
private Marker mCurrLocationMarker;
@Override
public void onPause() {
super.onPause();
//stop location updates when Activity is no longer active
if (mGoogleApiClient != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_live_watch);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
checkLocationPermission();
mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.mapFragment);
mapFragment.getMapAsync(this);
}
@Override
public void onMapReady(GoogleMap googleMap) {
mGoogleMap = googleMap;
mGoogleMap.setMyLocationEnabled(true);
//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);
}
}
public synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(getBaseContext())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
Log.d(TAG, "Inside onConnection Failed");
if (connectionResult.hasResolution()) {
try {
connectionResult.startResolutionForResult(this, CONNECTION_FAILURE_RESOLUTION_REQUEST);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "Exception error message : " + e.getMessage());
}
} else
Log.d(TAG, "Location services connection failed with code " + connectionResult.getErrorCode());
}
@Override
public void onConnected(@Nullable Bundle bundle) {
Log.d(TAG, "Connection established. Fetching location ..");
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);
} else if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
}
@Override
public void onConnectionSuspended(int i) {
Log.d(TAG, "Connection Suspended. Couldn't fetch location.");
}
@Override
public void onLocationChanged(Location 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);
mGoogleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15));
//stop location updates
if (mGoogleApiClient != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
}
// Check Runtime permissions for Marshmallow and above (API 23+) devices
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;
}
}
}
}
这是符合运行时权限的,如果您支持API 22+,即仅使用pre marshmallow设备,您可以删除运行时权限代码。