【问题标题】:Android find GPS location once, show loading dialogAndroid一次找到GPS位置,显示加载对话框
【发布时间】:2011-03-30 00:01:28
【问题描述】:

我正在编写一个应用程序,它需要用户的当前位置(lastknownlocation 不会很有帮助)并显示从数据库中获取的所有最接近他们的“项目”的列表。

我发现最近的项目运行良好,但暂时只使用硬编码的纬度和经度位置,但现在是时候实施查找实际位置了。

谁能提供一个示例,说明如何让应用在后台找到当前的精细位置并让应用等待。我只需要位置一次,不会随着人的移动而更新。我已经实现了一个位置监听器,但是我知道获取 GPS 修复可能会很慢。我已经看到使用最后一个已知位置或实现位置侦听器的其他示例,该侦听器继续运行和更新,但是因为我的 Activity 需要位置坐标才能显示应用程序崩溃的任何内容。我需要在搜索时显示一个进度对话框。

如何让 locationlistener 在后台运行一次,然后在找到位置后删除位置更新。我需要应用程序的其余部分等到它有 GPS 位置或在 20-30 秒后超时。我想要一个 ProgressDialog 以便用户知道正在发生的事情,但它必须是旋转加载动画而不是百分比或任何东西。如果可能的话,如果用户厌倦了等待,我希望用户能够取消对话框,然后他们可以通过输入郊区等来进行搜索。

我一直在尝试用线程来做,但它变得比我认为的要复杂得多,而且仍然无法正常工作。在 iPhone 上这要简单得多?

任何人都可以提供一个很好的方法来做到这一点,我已经为此烦恼了一个星期,这真的让我在应用程序完成日期的剩余时间里落后于计划。

总之,我想:
* 查找当前坐标
* 获取位置时显示进度对话框
* 应用是否可以等待定位成功或在一定时间后放弃?
* 如果成功:关闭进度对话框并使用坐标运行我的其他方法来查找附近的项目。
* 如果获取位置失败:关闭进度对话框并显示错误消息,并鼓励用户使用菜单转到搜索活动。
* 如果用户从菜单中选择地图视图,则使用这些坐标,以显示地图上的当前位置以及使用数据库中的坐标放置在所有附近项目上的图钉。

谢谢大家,我希望我已经对自己进行了充分的解释。任何问题只要问,我会定期检查,因为我渴望完成这部分。 干杯

编辑
按要求编码

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

这似乎真的只是为了获得一次当前位置而付出很大的努力吗?我不需要更新或任何东西?难道没有更简单的方法让应用程序等待结果吗?我在这个问题上卡了这么久。

【问题讨论】:

标签: android gps progressdialog locationlistener


【解决方案1】:

使用 AsyncTask 并使用 network_provider 和 gps_provider,这意味着两个侦听器。 gps 需要更长的时间才能得到修复,有时可能需要一分钟,而且只能在户外工作,而网络可以快速获取位置。

这里有一个很好的代码示例:What is the simplest and most robust way to get the user's current location on Android?

对于 AsyncTask,请查看 http://developer.android.com/reference/android/os/AsyncTask.html

这里也有很多关于它的代码示例,例如这里: Android Show a dialog until a thread is done and then continue with the program

编辑: 代码概念:

添加类变量

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;

异步任务: 保持原样,但不要打电话

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

在那里,而不是做

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

之间可能有延迟就足够了。

【讨论】:

  • 谢谢,这看起来很有帮助。我认为 GPS API 的东西无论如何都是异步的?还是我仍然需要实现它才能让应用程序等待结果?基于这些示例:那么我会从 doInBackground(final String...args) 中调用 myLocation.getLocation(this, locationResult) 吗?我只是不明白什么时候会调用 onPostExecute(final Void used),因为 MyLocation 东西的最终结果是 gotLocation(final Location location)?如果计时器用完会怎样?
  • 是的,gps 的东西是异步的,但显示进度不是。因此您需要将其包装在 AsyncTask 中,因为进度对话框取决于您的 gps 状态/结果。 onPostExecute 和 onPreExecute 在 UI 主线程上运行,因此您可以在其中更新您的 UI,例如,一旦您获得了 gps 修复,并在其中关闭进度对话框。
  • 好的,谢谢,我会试一试。 onPostExecute 如何知道我何时进行了 gps 修复或何时完成执行?即它如何知道何时调用了 gotLocation() 或计时器用完了?
  • 今天尝试使用 AsyncTask 并遇到问题。从 doInBackground 我调用 LocationHelper location = new LocationHelper();和 location.getLocation(params[0], locationResult);当它到达这条线时: locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListenerGps);它抛出异常:ERROR/AndroidRuntime(6534): Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() 请帮忙?
  • 到目前为止对我有好处,谢谢!不太确定将超时保持多长时间,因为获取 gps 或网络位置在我的设备上看起来如此善变,但我会继续测试值直到我满意为止。标记为已接受。 :)
【解决方案2】:

我仍然完全不喜欢它的工作原理,而且它似乎比它应该的要复杂得多,但是直到有人提供更好的方法,我现在让它工作......

如果有人遇到这种情况并建议一个更好的更清晰的结果,只需获取用户的当前位置坐标一次,然后停止查找,将不胜感激!

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

祝你好运,我需要它......

【讨论】:

  • 发布完整的工作代码(即 github)对您和我们来说都很棒 :)
【解决方案3】:

您为什么不创建一个 ProgressDialog 框并在public void gotLocation(final Location location){} 上将其关闭,而不是创建一个 AsyncTask?您还可以将 onCancelListener 添加到 ProgressDialog 框并取消任何当前位置请求。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-10-18
    • 2015-08-17
    • 1970-01-01
    • 2012-07-25
    • 2021-03-22
    • 1970-01-01
    • 1970-01-01
    • 2016-09-30
    相关资源
    最近更新 更多