web-dev-qa-db-fra.com

Android trouver une fois l'emplacement GPS, afficher la boîte de dialogue de chargement

J'écris une application qui nécessite l'emplacement actuel de l'utilisateur (la dernière localisation inconnue ne sera pas très utile) et affiche une liste de tous les "éléments" les plus proches d'eux, extraits de la base de données.

J'ai trouvé que les éléments les plus proches fonctionnaient bien, mais en utilisant uniquement un emplacement de latitude et de longitude codé en dur pour le moment, mais il est maintenant temps de mettre en œuvre la recherche de l'emplacement réel.

Quelqu'un peut-il fournir un exemple de la façon dont l'application trouve l'emplacement fin actuel en arrière-plan et fait attendre l'application? Je n'ai besoin que de l'emplacement une fois mis à jour lorsque la personne se déplace. J'ai implémenté un écouteur de localisation, mais je comprends que l'obtention d'une position GPS peut être lente. J'ai vu d'autres exemples utilisant le dernier emplacement connu ou mettant en œuvre l'écouteur d'emplacement qui continue de s'exécuter et de se mettre à jour, car mon activité a besoin des coordonnées de l'emplacement avant de pouvoir afficher tout ce que l'application plante. J'ai besoin d'afficher une boîte de dialogue de progression pendant sa recherche.

Comment puis-je faire en sorte que le programme d'écoute de localisation s'exécute une fois en arrière-plan, puis supprime les mises à jour de localisation une fois qu'il trouve l'emplacement. J'ai besoin que le reste de l'application attende d'avoir une position GPS ou un délai d'attente, disons 20-30 secondes. Je voudrais un ProgressDialog pour que l'utilisateur sache que quelque chose se passe, mais il doit juste s'agir d'une animation de chargement en rotation, pas d'un pourcentage ou de quoi que ce soit. Si possible, j'aimerais que l'utilisateur puisse annuler la boîte de dialogue s'il en a marre d'attendre, puis il peut rechercher en tapant suburb etc à la place.

J'ai essayé de le faire avec des threads mais cela devient beaucoup plus compliqué que je ne le pense et ne fonctionne toujours pas de toute façon. Sur iPhone, c'est beaucoup plus simple?

Quelqu'un peut-il fournir une belle façon de le faire, je me suis arraché les cheveux pendant une semaine à ce sujet et cela me met vraiment en retard pour le reste de la date d'achèvement de l'application.

En résumé, je veux:
* Trouver les coordonnées actuelles
* Afficher la boîte de dialogue de progression lors de la localisation
* Est-ce que l'application peut attendre le bon emplacement ou abandonner après un certain temps?
* En cas de succès: fermer la boîte de dialogue de progression et utiliser les coordonnées pour exécuter mes autres méthodes de recherche d'éléments à proximité.
* En cas d'échec d'obtention de l'emplacement: fermez la boîte de dialogue de progression et affichez le message d'erreur, et encouragez l'utilisateur à utiliser le menu pour accéder à l'activité de recherche.
* Utilisez ces coordonnées si l'utilisateur choisit l'affichage de la carte dans le menu, pour afficher l'emplacement actuel sur la carte et les repères déposés sur tous les éléments à proximité en utilisant leurs coordonnées dans la base de données.

Merci les gars, j'espère que je me suis bien expliqué. Pour toute question, je reviendrai régulièrement car je suis impatient de terminer cette partie. À votre santé

MODIFIER
Code tel que demandé

fichier d'activité locationList

protected void onStart()
{
    super.onStart();

    // ....

    new LocationControl().execute(this);
}


private class LocationControl extends AsyncTask<Context, Void, Void>
{
    private final ProgressDialog dialog = new ProgressDialog(branchAtmList.this);

    protected void onPreExecute()
    {
        this.dialog.setMessage("Determining your location...");
        this.dialog.show();
    }

    protected Void doInBackground(Context... params)
    {
        LocationHelper location = new LocationHelper();

        location.getLocation(params[0], locationResult);

        return null;
    }

    protected void onPostExecute(final Void unused)
    {
        if(this.dialog.isShowing())
        {
            this.dialog.dismiss();
        }

        useLocation(); //does the stuff that requires current location
    }

}

public LocationResult locationResult = new LocationResult()
{
    @Override
    public void gotLocation(final Location location)
    {
        currentLocation = location;
    }
};  

classe LocationHelper

    package org.xxx.xxx.utils;

import Java.util.Timer;
/*
imports
*/

public class LocationHelper
{
    LocationManager locationManager;
    private LocationResult locationResult;
    boolean gpsEnabled = false;
    boolean networkEnabled = false;

    public boolean getLocation(Context context, LocationResult result)
    {       
        locationResult = result;

        if(locationManager == null)
        {
            locationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
        }
            //exceptions thrown if provider not enabled
            try
            {
                gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
            }
            catch (Exception ex) {}
            try
            {
                networkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
            }
            catch (Exception ex) {}

            //dont start listeners if no provider is enabled
            if(!gpsEnabled && !networkEnabled)
            {
                return false;
            }

            if(gpsEnabled)
            {
                locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListenerGps);
            }
            if(networkEnabled)
            {
                locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListenerNetwork);
            }


            GetLastLocation();
            return true;
    }

    LocationListener locationListenerGps = new LocationListener() {
        public void onLocationChanged(Location location)
        {
            locationResult.gotLocation(location);
            locationManager.removeUpdates(this);
            locationManager.removeUpdates(locationListenerNetwork);

        }
        public void onProviderDisabled(String provider) {}
        public void onProviderEnabled(String provider) {}
        public void onStatusChanged(String provider, int status, Bundle extra) {}
    };

    LocationListener locationListenerNetwork = new LocationListener() {
        public void onLocationChanged(Location location)
        {
            locationResult.gotLocation(location);
            locationManager.removeUpdates(this);
            locationManager.removeUpdates(locationListenerGps);

        }
        public void onProviderDisabled(String provider) {}
        public void onProviderEnabled(String provider) {}
        public void onStatusChanged(String provider, int status, Bundle extra) {}

    };

    private void GetLastLocation()
    {
            locationManager.removeUpdates(locationListenerGps);
            locationManager.removeUpdates(locationListenerNetwork);

            Location gpsLocation = null;
            Location networkLocation = null;

            if(gpsEnabled)
            {
                gpsLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
            }
            if(networkEnabled)
            {
                networkLocation = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
            }

            //if there are both values use the latest one
            if(gpsLocation != null && networkLocation != null)
            {
                if(gpsLocation.getTime() > networkLocation.getTime())
                {
                    locationResult.gotLocation(gpsLocation);
                }
                else
                {
                    locationResult.gotLocation(networkLocation);
                }

                return;
            }

            if(gpsLocation != null)
            {
                locationResult.gotLocation(gpsLocation);
                return;
            }

            if(networkLocation != null)
            {
                locationResult.gotLocation(networkLocation);
                return;
            }

            locationResult.gotLocation(null);
    }

    public static abstract class LocationResult
    {
        public abstract void gotLocation(Location location);
    }
}

Cela semble vraiment être un gros effort pour obtenir une fois l'emplacement actuel? Je n'ai pas besoin de mises à jour ou quoi que ce soit? N'existe-t-il pas un moyen plus simple de faire attendre le résultat par l'application? Je suis coincé là-dessus depuis si longtemps.

26
Daniel Bowden

Utilisez un AsyncTask et utilisez à la fois network_provider et gps_provider , ce qui signifie deux auditeurs. le gps prend plus de temps pour obtenir un correctif, peut-être parfois une minute et ne fonctionne qu'à l'extérieur, tandis que le réseau obtient un emplacement assez rapidement.

Un bon exemple de code est ici: Quel est le moyen le plus simple et le plus robuste pour obtenir l'emplacement actuel de l'utilisateur sur Android?

Pour AsyncTask, regardez http://developer.Android.com/reference/Android/os/AsyncTask.html

Il existe également de nombreux exemples de code ici sur SO pour cela, par exemple ici: Android Afficher une boîte de dialogue jusqu'à ce qu'un thread soit terminé, puis continuer avec le programme

EDIT: concept de code:

ajouter une variable de classe

boolean hasLocation = false;

appeler dans onCreate (pas dans AsyncTask):

locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);

puis dans locationListener.onLocationChanged, changez la valeur une fois qu'un emplacement est trouvé:

boolean hasLocation = false;

AsyncTask: laissez tel quel, mais n'appelez pas

LocationHelper location = new LocationHelper();
location.getLocation(params[0], locationResult);

là, à la place

Long t = Calendar.getInstance().getTimeInMillies(); 
while (!hasLocation && Calendar.getInstance().getTimeInMillies()-t<30000)) {
    Thread.Sleep(1000); 
};    

probablement avec un délai entre les deux serait suffisant.

16
Mathias Conradt

Je n'aime toujours pas du tout comment cela fonctionne et cela semble beaucoup plus compliqué qu'il ne devrait l'être, mais jusqu'à ce que quelqu'un fournisse une meilleure façon de le faire fonctionner pour l'instant ...

Si quelqu'un tombe sur cela et suggère un résultat bien meilleur pour obtenir les coordonnées de localisation actuelles de l'utilisateur une seule fois, alors arrêtez de chercher ce serait grandement apprécié !!

private LocationControl locationControlTask;
private boolean hasLocation = false;
LocationHelper locHelper;

Depuis onCreate () j'appelle

locHelper = new LocationHelper();
locHelper.getLocation(context, locationResult);
locationControlTask = new LocationControl();
locationControlTask.execute(this);

J'ai ensuite une classe privée LocationControl

private class LocationControl extends AsyncTask<Context, Void, Void>
    {
        private final ProgressDialog dialog = new ProgressDialog(activityname.this);

        protected void onPreExecute()
        {
            this.dialog.setMessage("Searching");
            this.dialog.show();
        }

        protected Void doInBackground(Context... params)
        {
            //Wait 10 seconds to see if we can get a location from either network or GPS, otherwise stop
            Long t = Calendar.getInstance().getTimeInMillis();
            while (!hasLocation && Calendar.getInstance().getTimeInMillis() - t < 15000) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            };
            return null;
        }

        protected void onPostExecute(final Void unused)
        {
            if(this.dialog.isShowing())
            {
                this.dialog.dismiss();
            }

            if (currentLocation != null)
            {
                useLocation();
            }
            else
            {
                //Couldn't find location, do something like show an alert dialog
            }
        }
    }

Puis un emplacementRésultat ..

public LocationResult locationResult = new LocationResult()
    {
        @Override
        public void gotLocation(final Location location)
        {
            currentLocation = new Location(location);
            hasLocation = true;
        }
    };

De plus, pour éviter de vous arracher les cheveux comme je l'ai fait pendant des siècles, n'oubliez pas d'arrêter la tâche de localisation si quelqu'un quitte l'activité tôt et d'arrêter les mises à jour de position pour empêcher le GPS de fonctionner lorsque l'utilisateur quitte. Dans onStop (), faites quelque chose comme ceci:

locHelper.stopLocationUpdates();
locationControlTask.cancel(true);

StopLocationUpdates dans la classe Location Helper effectue également les opérations suivantes:

public void stopLocationUpdates()
{
locationManager.removeUpdates(locationListenerGps);
locationManager.removeUpdates(locationListenerNetwork);
}

Bonne chance, j'en avais besoin ...

12
Daniel Bowden

Au lieu de créer une AsyncTask, pourquoi n'avez-vous pas créé une boîte de dialogue ProgressDialog et l'avez-vous supprimée sur public void gotLocation(final Location location){}? Vous pouvez également ajouter un onCancelListener à la boîte de dialogue ProgressDialog et annuler toutes les demandes de localisation actuelles.

0
Carl