2015-04-15 17 views
28

Mam Android aplikacji, która potrzebuje aktualnej lokalizacji urządzenia (szerokość i długość geograficzna). Próbowałem już samouczek w sieci, a zwłaszcza niektóre rozwiązania z przepełnienia stosu, ale nie działają one dobrze dla mnie. Moje wymaganie jest takie proste: najpierw potrzebuję go, aby był szybki i potrzebował lokalizacji raz, gdy zaczyna się ten fragment. Po drugie, muszę być tak dokładny, jak to tylko możliwe, to znaczy, że powinien najpierw użyć GPS, jeśli GPS nie jest dostępny, a następnie użyć operatora sieci.uzyskać aktualną lokalizację szybko i raz w Androidzie

Na przykład wypróbowałem this solution, ale po 30 sekundach zwracam wartość null, ale wiem, że jest kilka rzeczy, ponieważ mapa google i inna aplikacja działa dobrze !!!

Coś, co prawie wszystkie odpowiedzi sugerują, to użycie metody getLastKnownLocation(), ale przypuszczam, że nie jest ona aktualna i nie chcę jej, jeśli tak jest.

Czy ktoś może zaproponować mi jakiś prosty i szybki sposób, aby uzyskać lokalizację właśnie RAZ?!

góry dzięki

Odpowiedz

46

Tutaj można to wykorzystać ...

Przykład użycia:

public void foo(Context context) { 
    // when you need location 
    // if inside activity context = this; 

    SingleShotLocationProvider.requestSingleUpdate(context, 
    new SingleShotLocationProvider.LocationCallback() { 
    @Override public void onNewLocationAvailable(GPSCoordinates location) { 
     Log.d("Location", "my location is " + location.toString()); 
    } 
    }); 
} 

Możesz chcieć zweryfikować lat/long są wartościami rzeczywistymi, a nie 0 lub coś. Jeśli dobrze pamiętam, nie powinienem podawać NPE, ale możesz to sprawdzić.

public class SingleShotLocationProvider { 

    public static interface LocationCallback { 
     public void onNewLocationAvailable(GPSCoordinates location); 
    } 

    // calls back to calling thread, note this is for low grain: if you want higher precision, swap the 
    // contents of the else and if. Also be sure to check gps permission/settings are allowed. 
    // call usually takes <10ms 
    public static void requestSingleUpdate(final Context context, final LocationCallback callback) { 
     final LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); 
     boolean isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); 
     if (isNetworkEnabled) { 
      Criteria criteria = new Criteria(); 
      criteria.setAccuracy(Criteria.ACCURACY_COARSE); 
      locationManager.requestSingleUpdate(criteria, new LocationListener() { 
       @Override 
       public void onLocationChanged(Location location) { 
        callback.onNewLocationAvailable(new GPSCoordinates(location.getLatitude(), location.getLongitude())); 
       } 

       @Override public void onStatusChanged(String provider, int status, Bundle extras) { } 
       @Override public void onProviderEnabled(String provider) { } 
       @Override public void onProviderDisabled(String provider) { } 
      }, null); 
     } else { 
      boolean isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); 
      if (isGPSEnabled) { 
       Criteria criteria = new Criteria(); 
       criteria.setAccuracy(Criteria.ACCURACY_FINE); 
       locationManager.requestSingleUpdate(criteria, new LocationListener() { 
        @Override 
        public void onLocationChanged(Location location) { 
         callback.onNewLocationAvailable(new GPSCoordinates(location.getLatitude(), location.getLongitude())); 
        } 

        @Override public void onStatusChanged(String provider, int status, Bundle extras) { } 
        @Override public void onProviderEnabled(String provider) { } 
        @Override public void onProviderDisabled(String provider) { } 
       }, null); 
      } 
     } 
    } 


    // consider returning Location instead of this dummy wrapper class 
    public static class GPSCoordinates { 
     public float longitude = -1; 
     public float latitude = -1; 

     public GPSCoordinates(float theLatitude, float theLongitude) { 
      longitude = theLongitude; 
      latitude = theLatitude; 
     } 

     public GPSCoordinates(double theLatitude, double theLongitude) { 
      longitude = (float) theLongitude; 
      latitude = (float) theLatitude; 
     } 
    } 
} 
+3

To działa jak czar, to wystarczająco szybko dla mnie, dzięki. – Evil

+0

nie działa, muszę dodać w moim manifeście? – delive

+1

Bardzo przydatne. Dziękuję Ci. –

1

Co chcesz zrobić, to uzyskać stosując LocationManager#requestSingleUpdate. Ta metoda dołącza detektor w danym looper (jeśli chcesz lub ma go) i powiadamia o lokalizacji, w której jest odbierany, tylko raz. Metoda, którą sugerujesz, jest używana tylko jako niedokładne położenie, zanim zostanie ci podana prawdziwa.

W każdym przypadku będzie szybsza niż milisekundy (chyba że masz szczęście rozpocząć słuchanie, gdy do urządzenia dotrze lokalizacja). Pomyśl o GPS jako o elemencie, który włączasz, czekając na lokalizację, i wyłączasz po usunięciu tego podsłuchu. Takie zachowanie jest wykonywane w celu uniknięcia wyczerpania baterii użytkownika.

Tak więc, aby podsumować:

  • Czas między wami zacząć słuchać i pojawić pozycja zależy od urządzenia GPS (produkcja, lokalizacji użytkownika, zasięg satelitarny ...)
  • Istnieje to metoda w zestawie SDK systemu Android do nasłuchiwania pojedynczej aktualizacji.
  • Dzięki udostępnieniu obiektu kryteriów można określić, które kryteria są akceptowalne, aby otrzymać lokalizację. Silniejsze kryteria oznaczają więcej czasu na uzyskanie dokładnej odpowiedzi.
0
// Get LocationManager object 
    LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); 

    // Create a criteria object to retrieve provider 
    Criteria criteria = new Criteria(); 

    // Get the name of the best provider 
    String provider = locationManager.getBestProvider(criteria, true); 

    // Get Current Location 
    Location myLocation = locationManager.getLastKnownLocation(provider); 

    //latitude of location 
    double myLatitude = myLocation.getLatitude(); 

    //longitude og location 
    double myLongitude = myLocation.getLongitude(); 

    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { 
     // TODO: Consider calling 
     // ActivityCompat#requestPermissions 
     // here to request the missing permissions, and then overriding 
     // public void onRequestPermissionsResult(int requestCode, String[] permissions, 
     //           int[] grantResults) 
     // to handle the case where the user grants the permission. See the documentation 
     // for ActivityCompat#requestPermissions for more details. 
     return; 
    } 
+0

Dlaczego instrukcja if używa "&&", a nie "||" ? potrzebujesz tylko jednego z uprawnień, aby uzyskać dostęp do lokalizacji? – DAVIDBALAS1

1

AndroidManifest.xml:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> 
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> 
<uses-feature android:name="android.hardware.location.gps" /> 

MainActivity.java:

public class MainActivity extends AppCompatActivity implements LocationListener { 

    private LocationManager locationManager; 
    private Location onlyOneLocation; 
    private final int REQUEST_FINE_LOCATION = 1234; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) 
      ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_FINE_LOCATION); 
    } 

    @Override public void onLocationChanged(Location location) { 
     onlyOneLocation = location; 
     locationManager.removeUpdates(this); 
    } 
    @Override public void onStatusChanged(String provider, int status, Bundle extras) { } 
    @Override public void onProviderEnabled(String provider) { } 
    @Override public void onProviderDisabled(String provider) { } 

    @Override 
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { 
     switch (requestCode) { 
     case REQUEST_FINE_LOCATION: 
      if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { 
       Log.d("gps", "Location permission granted"); 
       try { 
        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); 
        locationManager.requestLocationUpdates("gps", 0, 0, this); 
       } 
       catch (SecurityException ex) { 
        Log.d("gps", "Location permission did not work!"); 
       } 
      } 
      break; 
    } 
} 
1

AndroidManifest.xml

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> 
<uses-feature android:name="android.hardware.location.gps" /> 

Requesting User Permissions


build.gradle (moduł: app)

dependencies { 
    ... 
    implementation 'com.google.android.gms:play-services-location:11.8.0' 
    ... 
} 

Jeśli pojawi się błąd, sprawdź tha t najwyższego poziomu build.gradle zawiera odniesienie do pomocną() repo lub MAVEN {URL "https://maven.google.com"}

Set Up Google Play Services


LocationService.kt

import android.Manifest 
import android.annotation.SuppressLint 
import android.app.Activity 
import android.content.Intent 
import android.content.pm.PackageManager 
import android.location.Location 
import android.net.Uri 
import android.os.Looper 
import android.provider.Settings 
import android.support.v4.app.ActivityCompat 
import android.support.v4.content.ContextCompat 
import com.google.android.gms.common.api.ApiException 
import com.google.android.gms.common.api.ResolvableApiException 
import com.google.android.gms.location.* 
import org.jetbrains.anko.alert 
import org.jetbrains.anko.doAsync 
import org.jetbrains.anko.okButton 

object LocationService { 

    @SuppressLint("StaticFieldLeak") 
    private lateinit var fusedLocationProviderClient: FusedLocationProviderClient 
    private lateinit var locationRequest: LocationRequest 
    private val locationCallback = object : LocationCallback() { 
     override fun onLocationResult(locationResult: LocationResult) { 
      doAsync { 
       location = locationResult.lastLocation 
       onSuccess(location) 
      } 
     } 
    } 
    private lateinit var onSuccess: (location : Location) -> Unit 
    private lateinit var onError:() -> Unit 
    lateinit var location: Location 

    fun init(activity: Activity) { 
     fusedLocationProviderClient = FusedLocationProviderClient(activity) 
     locationRequest = LocationRequest().setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY).setInterval(1000).setFastestInterval(1000).setNumUpdates(1) 
    } 

    private fun checkLocationStatusAndGetLocation(activity: Activity) { 
     doAsync { 
      when { 
       ContextCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED -> LocationServices.getSettingsClient(activity).checkLocationSettings(LocationSettingsRequest.Builder().addLocationRequest(locationRequest).setAlwaysShow(true).build()).addOnCompleteListener { task -> 
        doAsync { 
         try { 
          task.getResult(ApiException::class.java) 
          fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper()) 
         } catch (exception: ApiException) { 
          when (exception.statusCode) { 
           LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> { 
            try { 
             (exception as ResolvableApiException).startResolutionForResult(activity, 7025) 
            } catch (ex: Exception) { 
             promptShowLocation(activity) 
            } 
           } 
           LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE -> { 
            promptShowLocation(activity) 
           } 
          } 
         } 
        } 
       } 
       ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.ACCESS_FINE_LOCATION) -> activity.runOnUiThread { 
        activity.alert("To continue, allow the device to use location, witch uses Google's Location Service") { 
         okButton { 
          val ite = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package", activity.packageName, null)) 
          ite.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 
          activity.startActivity(ite) 
          onError() 
         } 
         negativeButton("Cancelar", { onError() }) 
         onCancelled { onError() } 
        }.show() 
       } 
       else -> ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 7024) 
      } 
     } 
    } 

    private fun promptShowLocation(activity: Activity) { 
     activity.runOnUiThread { 
      activity.alert("To continue, allow the device to use location, witch uses Google's Location Service") { 
       okButton { 
        activity.startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)) 
        onError() 
       } 
       negativeButton("Cancelar", { onError() }) 
       onCancelled { onError() } 
      }.show() 
     } 
    } 

    fun onRequestPermissionsResult(activity: Activity, requestCode: Int, grantResults: IntArray) { 
     if (requestCode == 7024) { 
      if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { 
       checkLocationStatusAndGetLocation(activity) 
      } else { 
       onError() 
      } 
     } 
    } 

    fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int) { 
     if (requestCode == 7025) { 
      if (resultCode == Activity.RESULT_OK) { 
       checkLocationStatusAndGetLocation(activity) 
      } else { 
       onError() 
      } 
     } 
    } 

    fun getLocation(activity: Activity, onSuccess:() -> Unit, onError:() -> Unit) { 
     this.onSuccess = onSuccess 
     this.onError = onError 
     checkLocationStatusAndGetLocation(activity) 
    } 

} 

swoją aktywność

override fun onCreate(savedInstanceState: Bundle?) { 
    ... 
    LocationService.init(this) 
} 

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { 
    super.onRequestPermissionsResult(requestCode, permissions, grantResults) 
    LocationService.onRequestPermissionsResult(this, requestCode, grantResults) 
} 

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { 
    super.onActivityResult(requestCode, resultCode, data) 
    LocationService.onActivityResult(this, requestCode, resultCode) 
} 

private fun yourFunction() { 
    LocationService.getLocation(this, { location -> 
     //TODO: use the location 
    }, { 
     //TODO: display error message 
    }) 
}