android-永远不会调用OnLocationChanged回调

我正在尝试使用LocationManager来获取用户的当前位置。我进行了大量研究,但似乎找不到任何遇到相同问题的人。 requestSingleUpdate回调似乎从未被调用过。 下面是我的各种代码和logcat。

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

我的requestSingleUpdate方法

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

    this.context = getActivity();

    registerLocationUpdates();
}

我的requestSingleUpdate方法

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

我的requestSingleUpdate

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" />

最后是我运行我的应用程序后的日志猫

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使它在2.3设备上工作,并遵循指南A Dive Dive into Location,但我需要它在2.1或2.2及更高版本上工作 使用旧的SDK。 因此,如果您有任何提示或想了解更多信息,请告诉我。 提前致谢。

smitt04 asked 2019-10-09T16:21:36Z
13个解决方案
57 votes

看来您的安装程序应该可以正常工作,因为它不能正常工作,为了解决问题,我将尽可能简化您的示例。 我会让你的要求看起来像

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更新。

Steve Blackwell answered 2019-10-09T16:22:20Z
9 votes

更换

LocationManager.GPS_PROVIDER

LocationManager.NETWORK_PROVIDER

解决了我的问题。

这是我的位置管理器的代码段

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

//获取当前位置开始

        Location myLocation = locationManager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER);

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

//使用LocationManager.NETWORK_PROVIDER请求位置更新

        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
                MIN_TIME_BW_UPDATES,
                MIN_DISTANCE_CHANGE_FOR_UPDATES, MapFragment.this);
Hitesh Sahu answered 2019-10-09T16:23:47Z
6 votes

当设备处于低功耗或使用省电模式时,GPS Provider将禁用,在这种情况下,我们将无法接收GPS_PROVIDER

如果您呆在房屋或建筑物内,GPS Provider几乎不会返回位置(仅在室外工作良好)

因此,在我的应用中,我将同时使用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。

Phan Van Linh answered 2019-10-09T16:24:47Z
4 votes

正如史蒂夫·布莱克威尔(Steve Blackwell)所写,您的设置很好。 您可以尝试了解100%是否具有GPS固定信号! 我已经安装了一个不错的GPS Tester应用程序(来自Play商店),它将显示您是否有修复程序,以及连接到哪些卫星以及连接强度是多少。这就是我的OnLocationChanged()从未调用过的原因。我尝试从建筑物内运行它:\

祝好运!

Li3ro answered 2019-10-09T16:25:17Z
1 votes

我遇到了类似的问题。 我具有权限,可以正确请求服务,但是没有更新。 原来,我所要做的只是等待。 当我在Internet上搜索问题时,我正在运行该应用程序,几分钟后它才开始接收更新。 然后,即使我终止了该应用程序并再次运行它,更新也会立即出现-我猜这是系统问题,需要进行一些优化,也许是由于设备完全没有移动的事实(顺便说一句,它不是一些低劣的设备) ,它是Pixel)。

arenaq answered 2019-10-09T16:25:47Z
1 votes

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

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. 
VyTcdc answered 2019-10-09T16:26:22Z
0 votes

我遇到了同样的问题。 我正在将getLastKnownLocation设置为null。 重新启动设备和设备中的位置服务后,问题已解决。

Niranjan answered 2019-10-09T16:26:50Z
0 votes

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

  • 在模拟器上:从不工作
  • 在真实设备上:只有getLastKnownLocation()起作用,才能接收onLocationChanged(),您必须使用移动数据并出门,否则有可能因强盗而丢失手机:P

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

因此,我建议使用GPS_PROVIDER进行试验,然后再考虑性能和电池使用情况。 它在模拟器和真实设备上均能很好地工作。 最佳做法:[https://developer.android.com/guide/topics/location/strategies.html]

我花了几个小时来测试NETWORK_PROVIDER,但没有任何结果,因此希望我的建议对您有所帮助。

thanhbinh84 answered 2019-10-09T16:27:57Z
0 votes

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

Andrew Glukhoff answered 2019-10-09T16:28:27Z
0 votes

Phan Van Linh回答,可能是因为您在建筑物内。这里有关于如何为模拟器模拟GPS的说明。此外,还有这个应用程序可以模拟GPS数据。

dafnahaktana answered 2019-10-09T16:28:56Z
0 votes
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);
        }
}
Reza answered 2019-10-09T16:29:19Z
0 votes

很抱歉碰到这样一个旧线程,但这可能对其他一些用户很方便,因为这个问题在Google搜索中的排名相对较高。

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

该服务是前台服务,因此基于应该正常工作的Google文档,它不是!

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

这是我服务的方法:

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;

}
};

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

Emil Borconi answered 2019-10-09T16:30:47Z
0 votes

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

在Samsung上,一切正常且快速运行,找到了GPS坐标,并调用了PRIORITY_BALANCED_POWER_ACCURACY

在优先级为PRIORITY_BALANCED_POWER_ACCURACY的Vertex上,它可能首先与网络提供商进行交互,因此它通过Wi-Fi查找坐标。 但是它无法检测到是否打开了定位服务(在一段时间后设备认为它已打开,而关闭时又调用了LocationServices.getSettingsClientaddOnSuccessListener方法。因此,我切换到PRIORITY_HIGH_ACCURACY并得到另一个惊喜。网络提供商 关闭,但没有调用onLocationChanged,所以我无法获取坐标。我从Play Market下载了GPS tester(如@ Li3ro建议),发现卫星可见,但没有固定信号。我无法在内部接收信号 建筑。

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

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

CoolMind answered 2019-10-09T16:31:46Z
translate from https://stackoverflow.com:/questions/9007600/onlocationchanged-callback-is-never-called