web-dev-qa-db-ja.com

Android GPSの位置を一度検索し、読み込みダイアログを表示します

ユーザーの現在の場所を必要とするアプリを作成しています(最後の既知の場所はあまり役に立ちません)。データベースから取得した、ユーザーに最も近い「アイテム」のリストを表示します。

私は最も近いアイテムの発見をうまく機能させていますが、とりあえずハードコードされた緯度と経度の場所のみを使用していますが、実際の場所を見つけることを実装する時が来ました。

誰かがアプリにバックグラウンドで現在の良い場所を見つけてアプリを待つ方法の例を提供できますか?場所が必要なのは一度だけで、人が動いても更新されません。ロケーションリスナーを実装しましたが、GPSの修正が遅くなる可能性があることを理解しています。アクティビティが場所の座標を必要とするため、アプリがクラッシュするだけのものを表示する前に、最後に既知の場所を使用するか、実行と更新を続ける場所リスナーを実装する他の例を見てきました。検索中に進捗ダイアログを表示する必要があります。

Locationlistenerをバックグラウンドで1回実行し、場所が見つかったら場所の更新を削除する方法を教えてください。アプリケーションの残りの部分で、GPSの位置がわかるまで、または20〜30秒後にタイムアウトになるまで待機する必要があります。 ProgressDialogを上げて、何かが起こっていることをユーザーに知らせたいのですが、それはパーセンテージなどではなく、回転する読み込みアニメーションでなければなりません。可能であれば、ユーザーが待機にうんざりしている場合は、ダイアログをキャンセルして、代わりに郊外などと入力して検索できるようにしたいと考えています。

私はスレッドでそれをやろうとしましたが、それが思ったよりもずっと複雑になっていて、それでもうまくいきません。 iPhoneではこれはもっと簡単ですか?

誰かがこれを行うための素晴らしい方法を提供できますか?私はこれで1週間髪をはがしてきました、そしてそれは本当にアプリの残りの日付の予定より遅れています。

要約すると:
*現在の座標を検索
*位置を取得中に進捗ダイアログを表示
*アプリは、ロケーションが成功するのを待つことができますか、または一定時間後にあきらめることができますか?
*成功した場合:進捗ダイアログを閉じ、座標を使用して、近くにあるアイテムを見つけるための他の方法を実行します。
*位置の取得に失敗した場合:進行状況ダイアログを閉じてエラーメッセージを表示し、メニューを使用して検索アクティビティに移動するようユーザーに促します。
*ユーザーがメニューからマップビューを選択した場合、これらの座標を使用して、データベース上の座標を使用して、マップ上の現在の位置と、すべての近くのアイテムにドロップされたピンを表示します。

皆さん、ありがとうございます。質問があれば、この部分を完成させたいと思っているので、定期的にチェックします。乾杯

[〜#〜]編集[〜#〜]
要求通りのコード

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;
    }
};  

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);
    }
}

これは、現在の場所を一度取得するだけの大きな努力のように思えますか?アップデートなどは必要ありませんか?アプリケーションに結果を待つ簡単な方法はありませんか?私はずっとこれにこだわっています。

26
Daniel Bowden

AsyncTaskを使用し、network_providerとgps_providerの両方を使用して、つまり2人のリスナー。 gpsは修正を取得するのに時間がかかり、場合によっては1分で屋外でしか機能しませんが、ネットワークの場所はかなり高速です。

良いコード例は次のとおりです: Androidでユーザーの現在位置を取得する最も簡単で最も堅牢な方法は何ですか?

AsyncTaskについては、 http://developer.Android.com/reference/Android/os/AsyncTask.html を参照してください

ここにも多くのコード例がありますSOたとえば、ここにあります: Androidスレッドが完了するまでダイアログを表示し、プログラムを続行します

編集:コードの概念:

クラス変数を追加

boolean hasLocation = false;

onCreate(AsyncTaskではない)を呼び出します。

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

次に、locationListener.onLocationChangedで、場所が見つかったら値を変更します。

boolean hasLocation = false;

AsyncTask:そのままにしますが、呼び出さないでください

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

そこで、代わりに

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

おそらく間に遅れがあれば十分でしょう。

16
Mathias Conradt

私はまだこれがどのように機能するのか気に入らず、実際よりもはるかに複雑に見えますが、誰かがより良い方法を提供するまでは、今のところ機能させることができます...

誰かがこれに遭遇し、ユーザーの現在の位置の座標を一度だけ取得するためのより優れたよりクリーンな結果を提案したら、それを止めてください

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

OnCreate()から呼び出す

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

次に、プライベートクラス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
            }
        }
    }

次に、locationResult ..

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

また、私が昔からやってきたように髪の毛が抜けるのを防ぐために、誰かがアクティビティを早く離れた場合は位置制御タスクを停止し、ユーザーが離れたときに位置情報の更新を停止してGPSが実行されないようにしてください。 onStop()で次のようにします。

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

また、Location HelperクラスのstopLocationUpdatesは次のことを行います。

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

頑張って、私はそれを必要としていた...

12
Daniel Bowden

AsyncTaskを作成する代わりに、ProgressDialogボックスを作成してpublic void gotLocation(final Location location){}で閉じなかったのはなぜですか? onCancelListenerをProgressDialogボックスに追加して、現在のロケーション要求をキャンセルすることもできます。

0
Carl