Xamarin 位置服务 OnLocationChanged 不触发

Posted

技术标签:

【中文标题】Xamarin 位置服务 OnLocationChanged 不触发【英文标题】:Xamarin Location Service OnLocationChanged dont trigger 【发布时间】:2018-04-27 05:52:41 【问题描述】:

我们有一个问题,它在某些设备上随机发生,即无法触发 OnLocationChanged 事件。

LocationManager.RequestLocationUpdates(LocationManager.GpsProvider, 30000, 100, this);
LocationManager.RequestLocationUpdates(LocationManager.NetworkProvider, 30000, 100, this);

我们也尝试设置一个计时器,如果一分钟后事件没有触发,我们将尝试获取最后一个已知位置,但它仍然返回 null。

 CurrentLocation = LocationManager.GetLastKnownLocation(LocationManager.GpsProvider);
            LocationManager.RequestLocationUpdates(LocationManager.GpsProvider, 0, 0, this);

            if (CurrentLocation == null)//network provider
            
                CurrentLocation = LocationManager.GetLastKnownLocation(LocationManager.NetworkProvider);
                LocationManager.RequestLocationUpdates(LocationManager.NetworkProvider, 0, 0, this);
            

            if (CurrentLocation == null)//passive provider
            
                CurrentLocation = LocationManager.GetLastKnownLocation(LocationManager.PassiveProvider);
                LocationManager.RequestLocationUpdates(LocationManager.PassiveProvider, 0, 0, this);
            

我可以知道我的代码有什么问题吗?

已编辑(完整代码):

public class LocationService : Service, ILocationListener

    public IBinder Binder  get; private set; 
    public MainActivity MainAC  get  return m_ac;  set  m_ac = value;  
    public android.Locations.Location CurrentLocation  get; set; 
    public Android.Locations.LocationManager LocationManager  get; set; 
    public DateTime LastUpdateTime  get; set; 
    public bool IsMockLocation  get; set; 
    public string CurrentAddress  get; set; 
    public string CurrentCity  get; set; 

    private int iUpdateLocationInterval = 30000;// 30sec
    private int iUpdateLocationDistance = 100;// 100meter

    private int iUpdateLocationInterval_LastKnown = 0;// 0sec
    private int iUpdateLocationDistance_LastKnown = 0;// 0meter

    private System.Timers.Timer timerBackground = null;
    private MainActivity m_ac;
    private Lib.GoogleMaps google = new Lib.GoogleMaps();
    private bool bUpdateLocationIntervalUnknown = false;

    public LocationService()
    
    

    #region Override Function
    public override void OnCreate()
    
        base.OnCreate();
    

    [return: GeneratedEnum]
    public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
    
        StartCommandResult result = base.OnStartCommand(intent, flags, startId);

        return result;
    

    public override void OnDestroy()
    
        Binder = null;

        if (LocationManager != null)
        
            LocationManager.RemoveUpdates(this);
        

        base.OnDestroy();
    

    public override IBinder OnBind(Intent intent)
    
        // Return the communication channel to the service.

        this.Binder = new LocalLocationBinder(this);
        return this.Binder;
    
    #endregion

    private void StartBackgroundTimer()
    
        timerBackground = new System.Timers.Timer();
        timerBackground.Elapsed -= TimerBackground_Elapsed;
        timerBackground.Elapsed += TimerBackground_Elapsed;
        timerBackground.Interval = 10000;
        timerBackground.AutoReset = false;
        timerBackground.Enabled = true;
    

    private void TimerBackground_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    
        timerBackground.Enabled = false;

        try
         
            if (CurrentLocation == null)// OnLocationChanged didnt trigger, so get from last known location
            
                GetLastKnownLocation();
            
        
        catch  
    

    public void GetLastKnownLocation()
    
        m_ac.RunOnUiThread(() =>
        
            bUpdateLocationIntervalUnknown = true;
            CurrentLocation = LocationManager.GetLastKnownLocation(LocationManager.GpsProvider);
            LocationManager.RequestLocationUpdates(LocationManager.GpsProvider, iUpdateLocationInterval_LastKnown, iUpdateLocationDistance_LastKnown, this);

            if (CurrentLocation == null)//network provider
            
                CurrentLocation = LocationManager.GetLastKnownLocation(LocationManager.NetworkProvider);
                LocationManager.RequestLocationUpdates(LocationManager.NetworkProvider, iUpdateLocationInterval_LastKnown, iUpdateLocationDistance_LastKnown, this);
            

            if (CurrentLocation == null)//passive provider
            
                CurrentLocation = LocationManager.GetLastKnownLocation(LocationManager.PassiveProvider);
                LocationManager.RequestLocationUpdates(LocationManager.PassiveProvider, iUpdateLocationInterval_LastKnown, iUpdateLocationDistance_LastKnown, this);
            

            if (CurrentLocation != null)
            
                UpdateCurrentLocationInterval();
                ResolveGPSCoordinates(CurrentLocation);
            
            else
            
                m_ac.UpdateLocationName(Function.GetLanguage(m_ac, Resource.String.lblLocationServiceGetFailure));
            
        ); 
    

    // Location GPS
    public  void InitializeLocationManager()
    
        try
        
            m_ac.RunOnUiThread(() =>
            
                try
                
                    if (LocationManager != null) return;

                    LocationManager = (LocationManager)GetSystemService(LocationService);
                    Criteria criteriaForLocationService = new Criteria
                    
                        Accuracy = Accuracy.Fine
                    ;
                    IList<string> acceptableLocationProviders = LocationManager.GetProviders(criteriaForLocationService, true);

                    if (!LocationManager.IsProviderEnabled(LocationManager.GpsProvider))
                    
                        m_ac.ShowMessageToast(Function.GetLanguage(this, Resource.String.lblGPSLocationIsNotEnabled));
                        return;
                    

                    if (acceptableLocationProviders.Any())
                    
                        StartBackgroundTimer();
                        LocationManager.RequestLocationUpdates(LocationManager.GpsProvider, iUpdateLocationInterval, iUpdateLocationDistance, this);
                        LocationManager.RequestLocationUpdates(LocationManager.NetworkProvider, iUpdateLocationInterval, iUpdateLocationDistance, this);
                    
                    else
                    
                        m_ac.ShowMessageToast(Function.GetLanguage(this, Resource.String.lblGPSLocationIsNotEnabled));
                    
                
                catch(Exception ex)  m_ac.ShowMessageToast("ERROR:" + ex.Message); 
            );  

        
        catch (Exception ex)  m_ac.ShowMessageToast("ERROR:" + ex.Message); 
    

    private void UpdateCurrentLocationInterval()
    
        try
        
            if (LocationManager != null)
            
                bUpdateLocationIntervalUnknown = false ;
                LocationManager.RequestLocationUpdates(LocationManager.GpsProvider, iUpdateLocationInterval, iUpdateLocationDistance, this);
                LocationManager.RequestLocationUpdates(LocationManager.NetworkProvider, iUpdateLocationInterval, iUpdateLocationDistance, this);
            
        
        catch  
    

    public void OnLocationChanged(Location location)
    
        LastUpdateTime = DateTime.Now;
        IsMockLocation = true;
        CurrentLocation = location;
        CurrentAddress = string.Empty;
        CurrentCity = string.Empty;

        if (bUpdateLocationIntervalUnknown)
        
            UpdateCurrentLocationInterval();
        

        if (location.IsFromMockProvider)
        
            CurrentLocation = null;
            m_ac.UpdateLocationName(CurrentCity);
        
        else
        
            IsMockLocation = false;

            ResolveGPSCoordinates(location);
        
    

    private void ResolveGPSCoordinates(Location location)
    
        ResolveGPSCoordinatesAwait(location);
    

    private async void ResolveGPSCoordinatesAwait(Location location)
    
        int iResult = await google.ResolveLatLng(location.Latitude, location.Longitude);

        if (iResult == 0)
        
            CurrentAddress = google.AddressName;
            CurrentCity = google.CityName;

            if(CurrentCity == string.Empty)
                m_ac.UpdateLocationName(Function.GetLanguage(m_ac, Resource.String.lblLocationServiceGetFailure));
            else
                m_ac.UpdateLocationName(CurrentCity);
        
        else if (iResult == -2)
        
            m_ac.UpdateLocationName(Function.GetLanguage(m_ac, Resource.String.lblLocationServiceExceedAPIQuota));
        
        else
        
            if (string.IsNullOrEmpty(google.APIErrorMessage))
            
                m_ac.UpdateLocationName("ERROR:" + location.Latitude + "," + location.Longitude );
            
            else
            
                m_ac.UpdateLocationName(google.APIErrorMessage);
            
         
    

    public void OnProviderDisabled(string provider)
    
        if (provider.Equals(LocationManager.GpsProvider, StringComparison.InvariantCultureIgnoreCase))
        
            LastUpdateTime = DateTime.Now;
            IsMockLocation = false;
            CurrentLocation = null;
            CurrentAddress = string.Empty;
            CurrentCity = Function.GetLanguage(m_ac, Resource.String.lblLocationServiceDisable);

            m_ac.UpdateLocationName(CurrentCity);
        
    

    public void OnProviderEnabled(string provider)
    
        UpdateCurrentLocationInterval();
    

    public void OnStatusChanged(string provider, [GeneratedEnum] Availability status, Bundle extras)
    

    



public class LocationServiceConnection : Java.Lang.Object, IServiceConnection

    MainActivity m_ac = null;

    public LocationServiceConnection(MainActivity activity)
    
        m_ac = activity;
        IsConnected = false;
        Binder = null;
    

    public bool IsConnected  get; private set; 
    public LocalLocationBinder Binder  get; private set; 

    public void OnServiceConnected(ComponentName name, IBinder service)
    
        Binder = service as LocalLocationBinder;
        IsConnected = this.Binder != null;
        Binder.Service.MainAC = m_ac;
        Binder?.Service.InitializeLocationManager();
    

    public void OnServiceDisconnected(ComponentName name)
    
        IsConnected = false;
        Binder.Service.MainAC = null;
        Binder = null; 
     

    public void GetLastKnownLocation()
    
        Binder?.Service.GetLastKnownLocation();
    




#region LocalBinder
public class LocalLocationBinder : Binder

    public LocalLocationBinder(LocationService service)
    
        this.Service = service;
    

    public LocationService Service  get; private set; 
 
#endregion

【问题讨论】:

【参考方案1】:

好吧,我建议您检查是否提供了位置服务,我的意思是,如果不这样做,它们是否已打开,这样可以解决问题,您可以做的是,如果这些服务不可用,或者您可以说目前是拒绝,您可以简单地使用它来检查它是否可用,然后将您自己的代码应用于它,这可以确定您是否继续前进到地图页面。

 public class LocationEnabled : Fragment

    public GoogleApiClient googleApiClient;
  //  static int REQUEST_LOCATION = 199;
    public const int MIN_TIME_BW_UPDATES = 1000 * 3;
    public const int REQUEST_CHECK_SETTINGS = 9000;
    AppCompatActivity _activity;
    public LocationEnabled(AppCompatActivity activity)
    
        _activity = activity;
    
    private bool hasGPSDevice(Context context)
    
        LocationManager mgr = (LocationManager)context.GetSystemService(Context.LocationService);
        if (mgr == null)
            return false;
        IList<string> providers = mgr.AllProviders;
        if (providers == null)
            return false;
        return providers.Contains(LocationManager.GpsProvider);
    
    private async void enableLoc()
    
        if (googleApiClient == null)
        
            googleApiClient = new GoogleApiClient.Builder(_activity)
             .AddApi(LocationServices.API)
             .AddConnectionCallbacks(new CallBackHelper(googleApiClient))
             .AddOnConnectionFailedListener(new ConnectionFailedCallBack(_activity)).Build();

            googleApiClient.Connect();

            LocationRequest locationRequest = LocationRequest.Create();
            locationRequest.SetPriority(LocationRequest.PriorityHighAccuracy);
            locationRequest.SetInterval(MIN_TIME_BW_UPDATES);
            locationRequest.SetFastestInterval(MIN_TIME_BW_UPDATES/2);

            LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
              .AddLocationRequest(locationRequest);
            builder.SetAlwaysShow(true);

            LocationSettingsResult locationSettingsResult =
             await LocationServices.SettingsApi.CheckLocationSettingsAsync(googleApiClient, builder.Build());

            switch (locationSettingsResult.Status.StatusCode)
            
                case LocationSettingsStatusCodes.Success:
                    Toast.MakeText(_activity, "SUCCESS", ToastLength.Short).Show();
                    break;

                case LocationSettingsStatusCodes.ResolutionRequired:
                    try
                    
                        locationSettingsResult.Status.StartResolutionForResult(_activity, REQUEST_CHECK_SETTINGS);
                    
                    catch (Exception e)
                    
                        Toast.MakeText(_activity, "CANCEL: " + e.Message, ToastLength.Short).Show();
                    
                    break;

                default:
                    googleApiClient.Disconnect();
                    break;
            
        
    

    public override void OnCreate(Bundle savedInstanceState)
    
        base.OnCreate(savedInstanceState);
        LocationManager manager = (LocationManager)_activity.GetSystemService(Context.LocationService);
        if (manager.IsProviderEnabled(LocationManager.GpsProvider) && hasGPSDevice(_activity))
        
            Intent intent = new Intent(_activity, typeof(GoogleMapsActivity));
            StartActivity(intent);
        
        if (!hasGPSDevice(_activity))
        
              Toast.MakeText(_activity, "Gps not Supported", ToastLength.Long).Show();
        

        if (!manager.IsProviderEnabled(LocationManager.GpsProvider) && hasGPSDevice(_activity))
        
            enableLoc();              
        
        else
        

        
    

    public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    
        return base.OnCreateView(inflater, container, savedInstanceState);
    

public class ConnectionFailedCallBack : Java.Lang.Object, GoogleApiClient.IOnConnectionFailedListener

    Context _context;
    public ConnectionFailedCallBack(Context context)
    
        _context = context;
    
    public void OnConnectionFailed(ConnectionResult result)
    
        Toast.MakeText(_context, "Location connection failed.", ToastLength.Short).Show();
    

public class CallBackHelper : Java.Lang.Object, GoogleApiClient.IConnectionCallbacks

    GoogleApiClient googleApiClient;
    public CallBackHelper(GoogleApiClient googleApiClient)
    
        this.googleApiClient = googleApiClient;
    
    public void OnConnected(Bundle connectionHint)
    

    

    public void OnConnectionSuspended(int cause)
    
        googleApiClient.Connect();
    

并使用以下方法获取片段主机活动的结果:

  protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
    
        base.OnActivityResult(requestCode, resultCode, data);
        if (requestCode == LocationEnabled.REQUEST_CHECK_SETTINGS)
        
            switch (resultCode)
            
                case Result.Canceled:
                 //negative result 
                    break;

                case Result.Ok:
               //positive result 
                    break;

                case Result.FirstUser:
                default:
                    break;
            
        
    

祝你好运!

【讨论】:

设备已连接wifi并开启GPS定位,精度很高,但设备仍然无法获取位置。 你能更新你实现ILocationListener的代码吗@user2021195 那么你需要在一个活动或一个片段中拥有你的位置监听器才能被调用,否则它不会被调用@user2021195 也就是说,位置监听器不能放入服务? 是的,这就是我的理解

以上是关于Xamarin 位置服务 OnLocationChanged 不触发的主要内容,如果未能解决你的问题,请参考以下文章

Google Play 服务 - 位置 Xamarin Android

使用 google play 服务在 Xamarin 中获取用户位置

Xamarin Forms 使用 CrossGeolocator 获取前台服务位置更新

如何在 Xamarin.Forms 中创建永无止境的后台服务?

Xamarin 表单获取当前位置需要更多时间

Xamarin - 假地理位置