studio - location update android
FusedLocationApi.getLastLocation siempre nulo (9)
Aquí está la respuesta exacta y la explicación.
Simplemente me gustaría recuperar la ubicación del dispositivo en mi proyecto de Android y para hacerlo utilizo el enfoque de servicios de reproducción:
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder( MainSearchActivity.this )
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
@Override
public void onConnected( Bundle bundle ){
Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if( location == null ){
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, new LocationListener() {
@Override
public void onLocationChanged(Location location) {
lastLocation = location;
}
});
}
}
@Override
public void onConnectionSuspended( int i ){
}
})
.addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
@Override
public void onConnectionFailed( ConnectionResult connectionResult ){
if( connectionResult.hasResolution() ){
try {
// Start an Activity that tries to resolve the error
connectionResult.startResolutionForResult(MainSearchActivity.this, CONNECTION_FAILURE_RESOLUTION_REQUEST);
}catch( IntentSender.SendIntentException e ){
e.printStackTrace();
}
}else{
Utils.logger("Location services connection failed with code " + connectionResult.getErrorCode(), Utils.LOG_DEBUG );
}
}
})
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}
public Location retrieveLastLocation(){
Location loc = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if( loc == null)
{
}
return loc; //TODO: What if loc is null?
}
pero la variable loc SIEMPRE es nula. Es como tal en diferentes teléfonos, cada vez. También lastLocation, que trato de asignar en onLocationChanged, nunca cambia. Siempre nulo.
Estos son los permisos que configuré para la aplicación
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="com.vogella.android.locationapi.maps.permission.MAPS_RECEIVE" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
Simplemente no lo entiendo: ¿por qué los LocationServices no pueden recuperar una posición? Tengo todas las configuraciones de geolocalización habilitadas en los tres dispositivos que probé: - /
Gracias por cualquier ayuda
Como se dijo en this publicación, el proveedor de ubicación fusionada solo mantendrá la ubicación en segundo plano si al menos un cliente está conectado a ella.
Pero no queremos iniciar la aplicación Maps para obtener la última ubicación, y tampoco podemos decir que nuestros usuarios inicien la aplicación Maps para obtener la última ubicación.
Lo que necesitamos hacer es
- Tenemos que solicitar la actualización de ubicación de FusedLocationProviderClient
- Entonces podemos obtener la última ubicación de FusedLocationProviderClient , no sería nulo.
Solicitar ubicación
LocationRequest mLocationRequest = LocationRequest.create();
mLocationRequest.setInterval(60000);
mLocationRequest.setFastestInterval(5000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationCallback mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult == null) {
return;
}
for (Location location : locationResult.getLocations()) {
if (location != null) {
//TODO: UI updates.
}
}
}
};
LocationServices.getFusedLocationProviderClient(context).requestLocationUpdates(mLocationRequest, mLocationCallback, null);
Obtener la última ubicación
LocationServices.getFusedLocationProviderClient(context).getLastLocation().addOnSuccessListener(new OnSuccessListener<Location>() {
@Override
public void onSuccess(Location location) {
//TODO: UI updates.
}
});
Para obtener el mejor resultado en Inicio de la solicitud de Actividad para la actualización de ubicación, y luego puede obtener la última ubicación.
Creo que hay una pequeña falla que no es visible para mí en el código que se muestra.
mGoogleApiClient
está construido pero parece no estar conectado. Puede verificar esto llamando a
mGoogleApiClient.isConnected()
.
Puede anular el método onStart y llamar a connect allí.
O puede anular
onResume()
en caso de que desee acceder a la ubicación siempre que su actividad sea visible.
@Override
protected void onStart() {
super.onStart();
if (mGoogleApiClient != null) {
mGoogleApiClient.connect();
}
}
El
Location Provider
fusionado solo mantendrá la ubicación en segundo plano si al menos un cliente está conectado a él.
Ahora, solo activar el servicio de ubicación no garantizará almacenar la última ubicación conocida.
Una vez que se conecta el primer cliente, inmediatamente intentará obtener una ubicación.
Si su actividad es el primer cliente que se conecta y se invoca
getLastLocation()
inmediato en
onConnected()
, puede que no haya tiempo suficiente para que llegue la primera ubicación.
Le sugiero que inicie la aplicación Mapas primero, para que haya al menos alguna ubicación confirmada, y luego pruebe su aplicación.
Esto está relacionado con la respuesta de Amit K. Saha, pero para mí, en uno de mis dispositivos
Lollipop
seguía siendo
null
.
Así que abrí la aplicación de mapas y obtuve la siguiente pantalla pidiéndome que active todo ese jazz para mejorar mi ubicación.
Una vez que lo hice una vez, mi dispositivo pudo recibir la ubicación con solo una llamada a
getLastLocation()
;
Supongo que uno tendría que pedir estos permisos en la instalación de la aplicación para los usuarios que aún no hayan usado su aplicación de mapas.
Estoy usando el siguiente código para obtener la ubicación según la última documentación de Android https://developer.android.com/training/location/retrieve-current https://developer.android.com/training/location/receive-location-updates
MainActivity.java
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_CHECK_SETTINGS = 1;
private static final int REQUEST_GRANT_PERMISSION = 2;
private FusedLocationProviderClient fusedLocationClient;
LocationRequest locationRequest;
private Location currentLocation;
private LocationCallback locationCallback;
Button getUpdates,removeUpdates;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
createLocationRequest();
settingsCheck();
getUpdates = findViewById(R.id.button);
removeUpdates = findViewById(R.id.button2);
getUpdates.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ) {
ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.ACCESS_FINE_LOCATION},REQUEST_GRANT_PERMISSION);
return;
}
if(locationCallback==null)
buildLocationCallback();
if(currentLocation==null)
fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper());
}
});
removeUpdates.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ) {
ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.ACCESS_FINE_LOCATION},REQUEST_GRANT_PERMISSION);
return;
}
if(locationCallback!=null)
fusedLocationClient.removeLocationUpdates(locationCallback);
}
});
}
protected void createLocationRequest() {
locationRequest = LocationRequest.create();
locationRequest.setInterval(10000);
locationRequest.setFastestInterval(5000);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
// Check for location settings
public void settingsCheck() {
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest);
SettingsClient client = LocationServices.getSettingsClient(this);
Task<LocationSettingsResponse> task = client.checkLocationSettings(builder.build());
task.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {
@Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
// All location settings are satisfied. The client can initialize
// location requests here.
Log.d("TAG", "onSuccess: settingsCheck");
getCurrentLocation();
}
});
task.addOnFailureListener(this, new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
if (e instanceof ResolvableApiException) {
// Location settings are not satisfied, but this can be fixed
// by showing the user a dialog.
Log.d("TAG", "onFailure: settingsCheck");
try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
ResolvableApiException resolvable = (ResolvableApiException) e;
resolvable.startResolutionForResult(MainActivity.this,
REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException sendEx) {
// Ignore the error.
}
}
}
});
}
public void getCurrentLocation(){
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.ACCESS_FINE_LOCATION},1);
return;
}
fusedLocationClient.getLastLocation()
.addOnSuccessListener(this, new OnSuccessListener<Location>() {
@Override
public void onSuccess(Location location) {
Log.d("TAG", "onSuccess: getLastLocation");
// Got last known location. In some rare situations this can be null.
if (location != null) {
currentLocation=location;
Log.d("TAG", "onSuccess:latitude "+location.getLatitude());
Log.d("TAG", "onSuccess:longitude "+location.getLongitude());
}else{
Log.d("TAG", "location is null");
buildLocationCallback();
}
}
});
}
private void buildLocationCallback() {
locationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult == null) {
return;
}
for (Location location : locationResult.getLocations()) {
// Update UI with location data
currentLocation=location;
Log.d("TAG", "onLocationResult: "+currentLocation.getLatitude());
}
};
};
}
//called after user responds to location permission popup
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(requestCode==REQUEST_GRANT_PERMISSION){
getCurrentLocation();
}
}
//called after user responds to location settings popup
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d("TAG", "onActivityResult: ");
if(requestCode==REQUEST_CHECK_SETTINGS && resultCode==RESULT_OK)
getCurrentLocation();
if(requestCode==REQUEST_CHECK_SETTINGS && resultCode==RESULT_CANCELED)
Toast.makeText(this, "Please enable Location settings...!!!", Toast.LENGTH_SHORT).show();
}}
Archivo XML
<?xml version="1.0" encoding="utf-8"?><android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.locationexample.MainActivity">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="88dp"
android:text="getLocationUpdates"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.502"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="RemoveLocationUpdates"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button"
app:layout_constraintVertical_bias="0.363" /</android.support.constraint.ConstraintLayout>
Archivo de manifiesto
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.locationexample">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
Primero, cree un objeto
LocationRequest
:
// Create the LocationRequest object
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(10 * 1000) // 10 seconds, in milliseconds
.setFastestInterval(1 * 1000); // 1 second, in milliseconds
Luego, asegúrese de que el usuario haya otorgado permiso para usar la ubicación.
Si es así, obtenga la ubicación de
requestLocationUpdates
siguiente manera:
void getLocation() {
Location location = null;
if (ContextCompat.checkSelfPermission(activity, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
/*TODO!! INSERT CODE TO PROMPT USER TO GIVE PERMISSION*/
} else {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
mLastLocation = location;
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient,this);
}
Asegúrese de eliminar las actualizaciones si solo necesita una ubicación sin supervisión constante.
De esta manera, nunca obtendrá una
Location
nula.
Para obtener más información, vaya a blog.teamtreehouse.com/beginners-guide-location-android .
Si está utilizando Android Marshmallow (API 23) o una versión más reciente de Android, puede enfrentar el mismo problema porque no se otorga el permiso . Debe solicitar explícitamente el permiso en tiempo de ejecución para la ubicación o, si se trata de un proyecto de prueba, puede otorgar permiso de ubicación desde la configuración de la aplicación en su teléfono.
Si getLastLocation () siempre devuelve nulo, intente este truco. Lo he usado para resolver mi problema. Implemente LocationListener (import com.google.android.gms.location.LocationListener) en su actividad.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
Context mContext = this;
manager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
createLocationRequest();
mGoogleApiClient = new GoogleApiClient.Builder(mContext)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}
private void createLocationRequest(){
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(SET_INTERVAL);
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
}
onStart o onResume (prefiero onResume)
@Override
protected void onResume() {
super.onResume();
if (manager.isProviderEnabled(LocationManager.GPS_PROVIDER) ) {
if (mGoogleApiClient != null) {
mGoogleApiClient.connect();
}
}else{
// Showyourmesg();
}
}
@Override
protected void onPause() {
super.onPause();
if (mGoogleApiClient != null) {
mGoogleApiClient.disconnect();
}
}
protected void startLocationUpdates(){
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest,this);
}
protected void stopLocationUpdates() {
LocationServices.FusedLocationApi.removeLocationUpdates(
mGoogleApiClient, this);
}
Ahora, en su método onLocationChanged, verifique si googleApiClient está conectado o no. Si está conectado, desconéctelo y vuelva a conectarlo.
@Override
public void onLocationChanged(Location location) {
Log.d("SplashAct", "LocatinChngListner, loc: " + location.getLatitude() + "," + location.getLongitude());
if (mGoogleApiClient != null)
if (mGoogleApiClient.isConnected() || mGoogleApiClient.isConnecting()){
mGoogleApiClient.disconnect();
mGoogleApiClient.connect();
} else if (!mGoogleApiClient.isConnected()){
mGoogleApiClient.connect();
}
}
Y finalmente, en su método onConntected ()
@Override
public void onConnected(Bundle bundle) {
Log.d("ACTIVITY", "ApiClient: OnConnected");
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(
mGoogleApiClient);
if (mLastLocation == null){
startLocationUpdates(); // bind interface if your are not getting the lastlocation. or bind as per your requirement.
}
if (mLastLocation != null){
while (latitude == 0 || longitude == 0){
pDialog.setMessage("Getting Location");
pDialog.show();
latitude = mLastLocation.getLatitude();
longitude = mLastLocation.getLongitude();
if (latitude != 0 && longitude != 0){
stopLocationUpdates(); // unbind the locationlistner here or wherever you want as per your requirement.
pDialog.dismiss(); // location data received, dismiss dialog, call your method or perform your task.
}
}
}
}
Intentamos conectarnos repetidamente con googleApiClient, incluso si ya está conectado, para que podamos obtener los datos de lastLocation. Esto dependerá de los intervalos de LocationRequest. También puede obtener los datos de ubicación en onLocationChanged y realizar su tarea desde allí.