永远不会调用OnLocationChanged回调

时间:2012-01-25 17:53:57

标签: android geolocation locationmanager

我正在尝试使用LocationManager获取用户当前位置。我做了很多研究,似乎找不到任何有同样问题的人。似乎永远不会调用OnLocationChanged回调。下面是我的各种代码和logcat。

protected LocationListener locationListener;
protected LocationManager locationManager;
protected Context context;

我的OnCreate()方法

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.v(TAG, "IN ON CREATE");

    this.context = getActivity();

    registerLocationUpdates();
}

我的registerLocationUpdates方法

void registerLocationUpdates() {
    Criteria criteria = new Criteria();
    criteria.setAccuracy(Criteria.ACCURACY_LOW);
    criteria.setPowerRequirement(Criteria.POWER_LOW);
    criteria.setAltitudeRequired(false);
    criteria.setBearingRequired(false);

    locationManager = (LocationManager)getActivity().getSystemService(LOCATION_SERVICE);

    provider = locationManager.getBestProvider(criteria, true);

    // Cant get a hold of provider
    if (provider == null) {
        Log.v(TAG, "Provider is null");
        showNoProvider();
        return;
    } else {
        Log.v(TAG, "Provider: " + provider);
    }

    locationListener = new MyLocationListener();

    locationManager.requestLocationUpdates(provider, 1L, 1f, locationListener);

    // connect to the GPS location service
    Location oldLocation = locationManager.getLastKnownLocation(provider);

    if (oldLocation != null)  {
        Log.v(TAG, "Got Old location");
        latitude = Double.toString(oldLocation.getLatitude());
        longitude = Double.toString(oldLocation.getLongitude());
        waitingForLocationUpdate = false;
        getNearbyStores();
    } else {
        Log.v(TAG, "NO Last Location found");
    }
}

我的LocationListener

private class MyLocationListener implements LocationListener {

    public void onLocationChanged(Location location) {
        latitude = Double.toString(location.getLatitude());
        longitude = Double.toString(location.getLongitude());

        Log.v(TAG, "IN ON LOCATION CHANGE");

        if (waitingForLocationUpdate) {
            getNearbyStores();
            waitingForLocationUpdate = false;
        }

        locationManager.removeUpdates(this);
    }

    public void onStatusChanged(String s, int i, Bundle bundle) {
        Log.v(TAG, "Status changed: " + s);
    }

    public void onProviderEnabled(String s) {
        Log.e(TAG, "PROVIDER DISABLED: " + s);
    }

    public void onProviderDisabled(String s) {
        Log.e(TAG, "PROVIDER DISABLED: " + s);
    }
}

我在AndroidManifest中的权限

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

最后运行我的应用程序后的logcat

01-25 09:43:10.963: VERBOSE/NearbyListFragment(3060): IN ON CREATE
01-25 09:43:10.963: VERBOSE/LocationManagerService(1329): getProviders
01-25 09:43:10.963: VERBOSE/LocationManagerService(1329): getProviders
01-25 09:43:10.973: VERBOSE/LocationManagerService(1329): getProviders
01-25 09:43:10.983: VERBOSE/NearbyListFragment(3060): Provider: gps
01-25 09:43:10.983: DEBUG/LocationManager(3060): requestLocationUpdates: provider = gps, listener = co.fusionweb.dealsplus.app.NearbyItems$NearbyListFragment$MyLocationListener@46ef4680
01-25 09:43:10.983: DEBUG/GpsLocationProvider(1329): setMinTime 1
01-25 09:43:10.983: VERBOSE/NearbyListFragment(3060): NO Last Location found
01-25 09:43:10.983: VERBOSE/LocationManagerService(1329): _requestLocationUpdates: listener = Receiver{47421e68 Listener android.os.BinderProxy@47421a68}
01-25 09:43:11.003: VERBOSE/countingFragment(3060): IN ON CREATE VIEW
01-25 09:43:11.003: WARN/GpsLocationProvider(1329): Duplicate add listener for co.fusionweb.dealsplus
01-25 09:43:11.013: VERBOSE/ScrollListener(3060): In Constructor
01-25 09:43:11.013: VERBOSE/ScrollListener(3060): Scrolling
01-25 09:43:11.033: DEBUG/GpsLocationProvider(1329): startNavigating
01-25 09:43:11.043: DEBUG/lib_locapi(1329): loc_eng_set_qos_time_out(standalone = 60, agps = 89)
01-25 09:43:11.043: DEBUG/lib_locapi(1329): loc_eng_set_qos_accuracy(accuracy = 50)
01-25 09:43:11.043: VERBOSE/lib_locapi(1329): persist.radio.agps.mode: []
01-25 09:43:11.043: DEBUG/lib_locapi(1329): loc_eng_set_position mode, client = 1, interval = 1, mode = 1
01-25 09:43:11.043: VERBOSE/lib_locapi(1329): loc_eng_ioctl called: client = 1, ioctl_type = 2
01-25 09:43:11.043: VERBOSE/locapi_rpc_glue(1329): loc_ioctl
01-25 09:43:11.043: DEBUG/RPC(1329): written RPC packet size: [96]
01-25 09:43:11.043: DEBUG/RPC(1329): read RPC packet
01-25 09:43:11.043: DEBUG/RPC(1329): read RPC packet size: [28]
01-25 09:43:11.043: VERBOSE/locapi_rpc_glue(1329): loc_api_sync_ioctl: select_id = 0, loc_ioctl returned 0
01-25 09:43:11.043: DEBUG/RPC(1329): read RPC packet
01-25 09:43:11.043: DEBUG/RPC(1329): read RPC packet size: [80]
01-25 09:43:11.043: VERBOSE/locapi_rpc_glue(1329): Callback received: 80 (cb_id=0x5310000 handle=1)
01-25 09:43:11.043: DEBUG/RPC(1329): written RPC packet size: [28]
01-25 09:43:11.043: VERBOSE/lib_locapi(1329): loc_eng_ioctl result: client = 1, ioctl_type = 2, SUCCESS
01-25 09:43:11.043: DEBUG/lib_locapi(1329): loc_eng_start
01-25 09:43:11.043: DEBUG/locapi_rpc_glue(1329): loc_start_fix
01-25 09:43:11.043: DEBUG/RPC(1329): written RPC packet size: [44]
01-25 09:43:11.043: DEBUG/RPC(1329): read RPC packet
01-25 09:43:11.053: DEBUG/RPC(1329): read RPC packet size: [28]
01-25 09:43:11.103: DEBUG/RPC(1329): read RPC packet
01-25 09:43:11.103: DEBUG/RPC(1329): read RPC packet size: [80]
01-25 09:43:11.113: VERBOSE/locapi_rpc_glue(1329): Callback received: 100 (cb_id=0x5310000 handle=1)
01-25 09:43:11.113: VERBOSE/lib_locapi(1329): process_deferred_action: pthread_cond_wait returned
01-25 09:43:11.113: DEBUG/lib_locapi(1329): loc_eng_report_status: GPS_STATUS_SESSION_BEGIN
01-25 09:43:11.113: DEBUG/lib_locapi(1329): loc_eng_report_status: update status
01-25 09:43:11.113: VERBOSE/GpsLocationProvider(1329): reportStatus status: 1
01-25 09:43:11.113: DEBUG/GpsLocationProvider(1329): Acquiring wakelock
01-25 09:43:11.123: DEBUG/RPC(1329): written RPC packet size: [28]
01-25 09:43:11.183: DEBUG/PowerManagerService(1329): New lightsensor value:40, lcdValue:77
01-25 09:43:11.273: DEBUG/RPC(1329): read RPC packet
01-25 09:43:11.273: DEBUG/RPC(1329): read RPC packet size: [80]
01-25 09:43:11.273: VERBOSE/locapi_rpc_glue(1329): Callback received: 100 (cb_id=0x5310000 handle=1)
01-25 09:43:11.273: VERBOSE/lib_locapi(1329): process_deferred_action: pthread_cond_wait returned
01-25 09:43:11.273: DEBUG/lib_locapi(1329): loc_eng_report_status: GPS_STATUS_ENGINE_ON
01-25 09:43:11.273: DEBUG/lib_locapi(1329): loc_eng_report_status: update status
01-25 09:43:11.273: VERBOSE/GpsLocationProvider(1329): reportStatus status: 3

并且logcat的android SDK位置部分不断重复它们。我已经尝试了一些我能想到并在google和stackoverflow上看到过的东西。 Als只是作为附注,我已经能够使用API​​ 9中提供的requestSingleUpdate并遵循指南A Deep Dive into Location使其在2.3设备上工作但我需要它在2.1上工作使用旧的SDK或2.2及更高版本。如果您有任何提示或想了解更多,请告诉我。提前谢谢。

16 个答案:

答案 0 :(得分:57)

看起来你的设置应该可行,因为它没有,我会让你的例子尽可能简单,以便排除故障。我会让你的请求看起来像

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

这样您就可以获得所有更新。并评论关于获取最后已知位置的部分。它还不需要。

然后在onLocationChanged()中,只有

Log.v(TAG, "IN ON LOCATION CHANGE, lat=" + latitude + ", lon=" + longitude);

注释掉其余部分,以便让你的听众保持活跃状态​​。这应该会为您提供真实设备上的更新流。在模拟器上,您需要使用DDMS,每次按下发送时都会获得一次GPS更新。

答案 1 :(得分:10)

更换

  

LocationManager.GPS_PROVIDER

  

LocationManager.NETWORK_PROVIDER

解决了我的问题。

以下是我的位置管理员的代码段

var pageViewController: UIPageViewController?
override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    // Configure the page view controller and add it as a child view controller.
    self.pageViewController = UIPageViewController(transitionStyle: .pageCurl, navigationOrientation: .horizontal, options: nil)
    self.pageViewController!.delegate = self

    let startingViewController: DataViewController = self.modelController.viewControllerAtIndex(0, storyboard: self.storyboard!)!
    let viewControllers = [startingViewController]
    self.pageViewController!.setViewControllers(viewControllers, direction: .forward, animated: false, completion: {done in })

    self.pageViewController!.dataSource = self.modelController

    self.addChildViewController(self.pageViewController!)
    self.view.addSubview(self.pageViewController!.view)

    // Set the page view controller's bounds using an inset rect so that self's view is visible around the edges of the pages.
    var pageViewRect = self.view.bounds
    if UIDevice.current.userInterfaceIdiom == .pad {
        pageViewRect = pageViewRect.insetBy(dx: 40.0, dy: 40.0)
    }
    self.pageViewController!.view.frame = pageViewRect

    self.pageViewController!.didMove(toParentViewController: self)
}

//检查位置权限,Marshmallow及以上

 LocationManager locationManager = (LocationManager) getActivity().getSystemService(LOCATION_SERVICE);

//获取当前位置

        if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                && ActivityCompat.checkSelfPermission(getActivity(), 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.

            Toast.makeText(getActivity(), "Not Enough Permission", Toast.LENGTH_SHORT).show();
            return;
        }

//使用LocationManager.NETWORK_PROVIDER

请求位置更新
        Location myLocation = locationManager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER);

        currentLatitude = myLocation.getLatitude();
        currentLongitude = myLocation.getLongitude();

答案 2 :(得分:7)

当设备处于低功耗状态或使用省电模式时,GPS提供商将禁用,那么在这种情况下我们无法接收onLocationChanged

如果您呆在房屋或建筑物内(仅在户外工作良好),GPS提供商几乎不会返回

因此,在我的应用中,我会同时使用GPS_PROVIDERNETWORK_PROVIDER来更好地接收onLocationChanged()

https://developer.android.com/guide/topics/location/strategies.html#Updates

  

要从GPS提供商处请求位置更新,请使用GPS_PROVIDER   而不是NETWORK_PROVIDER。您还可以请求位置更新   通过呼叫从GPS和网络位置提供商   requestLocationUpdates()两次 - 一次用于NETWORK_PROVIDER,一次用于   GPS_PROVIDER。

答案 3 :(得分:4)

史蒂夫布莱克威尔写道,你的设置很好。您可以尝试的是了解您是否100%拥有GPS固定信号!我已经安装了一个不错的GPS Tester application (from the play store),它会告诉你是否有修复,以及你连接的卫星和连接强度是多少。 这就是我的OnLocationChanged()永远不会调用的原因..我尝试在建筑物内运行它:\

祝你好运!

答案 4 :(得分:1)

我遇到了类似的问题。我有权限,请求正确服务,但没有更新。事实证明,我所要做的只是等待。当我在互联网上搜索问题时,我运行了应用程序,几分钟后它才开始接收更新。然后,即使我杀了应用程序并再次运行它,更新即时发生 - 我想这是一个系统的事情,一些优化,可能是因为设备根本没有移动(顺便说一下。它不是一些糟糕的设备,它是Pixel)。

答案 5 :(得分:1)

我有相同的情况,我以为我在我的代码中犯了一些错误所以onlocationchage方法没有被调用,最后我像这样解决了。

Step 1 :
Close your application and Open Google Map Application.

Step 2 :
Touch the location finder button or icon over the Google Map app then It will show, currently where you are located.

Step 3 :
Now Run your app and check onlocationchage will call. 

答案 6 :(得分:0)

我遇到了同样的问题。我的getLastKnownLocation为null。当我在设备中重新启动设备和位置服务时,问题得以解决。

答案 7 :(得分:0)

如果您尝试使用NETWORK_PROVIDER,则很难进行测试:

  • on Emulator:永远不会工作
  • 在Real Device上:只有getLastKnownLocation()工作,要接收onLocationChanged(),你必须使用移动数据,并冒着失去强盗手机的风险:P

我想原因是它只是网络提供商的位置而不是你的设备本身,而网络提供商从不移动,所以onLocationChanged()从不调用。它可能仅在移动数据和wifi之间切换时发生,反之亦然。如果我错了,请纠正我。

所以我建议在考虑性能和电池使用情况之前使用GPS_PROVIDER进行实验。它在仿真器和真实设备上都能很好地工作。最佳做法:https://developer.android.com/guide/topics/location/strategies.html

使用NETWORK_PROVIDER进行测试花了几个小时没有任何结果,所以希望我的建议很有帮助。

答案 8 :(得分:0)

我在我的真实设备(M,应用程序的targetSDK 23)上遇到了同样的问题(onLocationChanged()从未使用NETWORK_PROVIDER调用),直到我重新启动它。

答案 9 :(得分:0)

正如Phan Van Linh所回答的那样,可能是因为你在建筑物内。 有关如何为模拟器模拟GPS的解释here。 此外,有this应用程序可以嘲笑GPS数据。

答案 10 :(得分:0)

LocationManager manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
if (manager != null) {
        List<String> providers = manager.getAllProviders();
        for (String provider : providers) {
           manager.requestLocationUpdates(provider, TIME_BW_UP, DISTANCE_BW_UP, locationListener);
        }
}

答案 11 :(得分:0)

很抱歉碰到这样一个老话题,但这可能对其他人来说很方便,因为这个问题在Google搜索中的排名相对较高。

我有一个类似的问题,onlocationchanged没有被解雇,但是我的代码找不到任何错误。在尝试了各种组合之后,我意识到问题的根本原因是我在服务中注册了侦听器。

该服务是一项前台服务,因此基于应该工作的Google documentation,它没有作用!

在方法中包装初始化,然后从创建或绑定到服务的活动中调用该方法解决了我的问题。

这是我提供服务的方法:

void start_gps_track(int i) {
        if (myCarLocationListener!=null) {
            if (i==1) //if start night
                myCarLocationListener.setNightstart(true);
            else if (i==2) //if start GPS
                myCarLocationListener.setLocationStart(true);
            return;
        }
        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        if ( locationManager.isProviderEnabled( LocationManager.GPS_PROVIDER ) ) {
            myCarLocationListener=new CarLocationListener(this,adjust_audio);
            if (i==1) //if start night
                myCarLocationListener.setNightstart(true);
            else if (i==2) //if start GPS
                myCarLocationListener.setLocationStart(true);
            try {
                locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 100, 0, myCarLocationListener);
                Log.d("HU","Registered location listener");
                Location lastlocation = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
                if (lastlocation == null)
                    lastlocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
                if (lastlocation != null)
                    myCarLocationListener.onLocationChanged(lastlocation);
            }
            catch (SecurityException e){
                Log.e("HU-GPS","No permission to access Location");
            }
        }
        else
        {
            Log.e("HU-GPS","No GPS provider or no permission");
        }
    }

如果我从服务本身内部调用它,我将不会收到任何位置更新信息(再次注意,该服务是一项FOREGROUND服务,它实际上已绑定到当前正在运行的活动)。

但是,如果我从创建/绑定到该服务的活动中调用此方法,如下所示,它就可以正常工作:

@Override
public void onServiceConnected(ComponentName className,
                               IBinder service) {
    // We've bound to LocalService, cast the IBinder and get LocalService instance
    TransporterService.LocalBinder binder = (TransporterService.LocalBinder) service;
    mService = binder.getService();
    mService.updatePlayer(player.this);
    try {
        mService.start_gps_track(0);
    }
    catch (Exception e) {            //This should only happen if there is no GPS provider available, but it might happen quickly after boot when the device is not yet ready.
        mService.recheck_gps(0);
    }

    mBound = true;
  }

@Override
public void onServiceDisconnected(ComponentName arg0) {
    mBound = false;

}
};

希望这对遇到此问题的其他人有所帮助。

答案 12 :(得分:0)

我有2台设备:Samsung Galaxy S4(Android 5.0.1)和Vertex Win(Android 8.1)。

在Samsung上,一切正常且快速,可以找到GPS坐标,并调用onLocationChanged

在顶点PRIORITY_BALANCED_POWER_ACCURACY中的顶点上,它可能首先与网络提供商进行交互,因此它通过Wi-Fi查找坐标。但是它无法检测到是否打开了定位服务(在一段时间后设备认为它已打开,而关闭时又调用了addOnSuccessListener的{​​{1}}方法。因此,我切换到LocationServices.getSettingsClient并带来另一个惊喜。网络提供商已关闭,但未致电PRIORITY_HIGH_ACCURACY,因此我无法获取坐标。我从Play Market下载了onLocationChanged(按照@ Li3ro的建议)看到卫星可见,但没有固定信号。我无法在建筑物内接收到信号。

即使是独立的地图也无法接收坐标,而户外的则可以。因此,走开后,我可以在应用程序中找到我的协调人。

另请参阅https://stackoverflow.com/a/27828929/2914140,其中提到了优先级和错误识别(如果找不到协调人,则在一段时间后禁用GPS)。

答案 13 :(得分:0)

这可能是由于您的手机设置导致的。在手机的“位置”设置中,如果“位置服务模式”设置为“仅GPS”,则在有GPS修复功能时,OnLocationChanged回调电话将呼叫。通过选择“使用GPS,WI-FI和移动网络”选项,将通过使用这三个提供商来确定位置。这将花费更少的时间来定位您的设备位置。 ***访问位置服务的路径可能是将设备更改为设备。 谢谢

答案 14 :(得分:0)

关闭位置后,这发生在我身上。不是应用程序的位置权限,而是android设备本身的位置。要求用户激活GPS为我修复它:

protected void onCreate(Bundle savedInstanceState) {
    //...
    final LocationManager manager = (LocationManager) getSystemService( Context.LOCATION_SERVICE );

    if ( !manager.isProviderEnabled( LocationManager.GPS_PROVIDER ) ) {
        buildAlertMessageNoGps();
    }
}

private void buildAlertMessageNoGps() {
    final AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setMessage("Your GPS seems to be disabled, do you want to enable it?")
            .setCancelable(false)
            .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                public void onClick(@SuppressWarnings("unused") final DialogInterface dialog, @SuppressWarnings("unused") final int id) {
                    startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
                }
            })
            .setNegativeButton("No", new DialogInterface.OnClickListener() {
                public void onClick(final DialogInterface dialog, @SuppressWarnings("unused") final int id) {
                    dialog.cancel();
                }
            });
    final AlertDialog alert = builder.create();
    alert.show();
}

来自here的解决方案。

您可能还需要先关闭GPS,然后再打开,以触发对话框以提高定位精度:

Dialog prompting to improve location accuracy

答案 15 :(得分:0)

就我而言,即使编写了正确的代码,我也没有使用 client.requestLocationUpdates(locationRequest, this, it) 获取位置。 在手机中也启用了 GPS 使用

val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
startActivity(intent)

在切换模拟器、构建等方面花费时间后,终于发现位置模式是“仅限设备”,并且没有在模拟器上提供结果。切换到“高精度”并开始工作。