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 获取前台服务位置更新