0
\$\begingroup\$

I made the below CurrentLocationTask as a way of reducing code duplication, as my application currently has 2 different Activitys which both use GoogleApiClient and OnLocationChanged.

The task basically connects a GoogleApiClient, then uses a LocationRequest to subscribe to RequestLocationUpdates.

In the OnLocationChanged method, CurrentLocation is updated, and the PropertyChanged event is fired.

Because the PropertyChangedEventHandler is public, it can be subscribed to from the required Activity. So the task can be called from an Activity on which we need to get the user's current location.

Usage

OnCreate

Create a new CurrentLocationTask and Execute, passing in the current activity as context. Then subscribe to the PropertyChanged event with OnCurrentLocationChanged:

protected override void OnCreate(Bundle bundle)
{
 base.OnCreate(bundle);
 SetContentView(Resource.Layout.Main);
 // Subscribe to current location
 _currentLocationTask = new CurrentLocationTask();
 _currentLocationTask.Execute(this);
 _currentLocationTask.PropertyChanged += OnCurrentLocationChanged;
}

OnCurrentLocationChanged

We can get CurrentLocation from the CurrentLocationTask:

private void OnCurrentLocationChanged(object sender, PropertyChangedEventArgs e)
{
 _currentLocation = _currentLocationTask.CurrentLocation;
}

OnStop

In OnStop, Disconnect the GoogleApiClient:

protected override void OnStop()
{
 base.OnStop();
 _currentLocationTask.Client.Disconnect();
}

The code for the AsyncTask is below. Any recommendations are much appreciated.

I'm not sure if using AsyncTask is the best way of doing this, especially since I don't think very much of the code here is actually being called in RunInBackground.

CurrentLocationTask

using System.Linq;
using System.ComponentModel;
using Android.OS;
using Android.Gms.Common.Apis;
using Android.Gms.Common;
using Android.Gms.Location;
using Android.Locations;
using Android.Content;
namespace WeatherApp.Droid
{
 class CurrentLocationTask : 
 AsyncTask<Context, int, Java.Lang.Void>,
 GoogleApiClient.IConnectionCallbacks,
 GoogleApiClient.IOnConnectionFailedListener,
 Android.Gms.Location.ILocationListener,
 INotifyPropertyChanged
 {
 public event PropertyChangedEventHandler PropertyChanged;
 public Location CurrentLocation { get; set; }
 public GoogleApiClient Client;
 private LocationRequest _locationRequest;
 private Context _context;
 // AsyncTask
 protected override Java.Lang.Void RunInBackground(params 
 Context[] context)
 {
 _context = context.First();
 // Build the client and connect
 Client = 
 new GoogleApiClient.Builder(_context)
 .AddApi(LocationServices.API)
 .AddConnectionCallbacks(this)
 .Build();
 Client.Connect();
 return null;
 }
 // API connection
 public void OnConnected(Bundle connectionHint)
 {
 _locationRequest = LocationRequest.Create();
 _locationRequest.SetPriority(LocationRequest.PriorityHighAccuracy);
 _locationRequest.SetInterval(1000);
 LocationServices.FusedLocationApi.RequestLocationUpdates(
 Client, _locationRequest, this);
 }
 public void OnConnectionFailed(ConnectionResult result)
 {
 MessageBox.Show(_context, "Connection Failed");
 }
 public void OnConnectionSuspended(int cause)
 {
 MessageBox.Show(_context, "Connection Suspended");
 }
 // Location changed
 public void OnLocationChanged(Location location)
 {
 CurrentLocation = location;
 PropertyChanged?.Invoke(this,
 new PropertyChangedEventArgs("CurrentLocation"));
 }
 }
}
asked Apr 22, 2017 at 13:55
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

Note: the following refers to native Android development, I am not familiar with xamarin.

About the approach It depends on what your aim is. The downside of using AsyncTask is that it's tied to the Activity you're calling it from. I recently implemented continuous location tracking, where AsyncTasks were not an option, as the process of continuous tracking is not tied to a particular activity. So I opted for an Android Service implementation instead. The Service was in it's own class and while you could bind to a service in a given Activity I instead went for the EventBus pattern (there are other options though) - meaning every time the LocationService obtained a new location it would cache the most recent location and propagate an Event via the Eventbus. This way subscribers (such as Activities) would be informed of location changes and could update the UI accordingly.

However, if you only want to query for locations within the Map Activity, then an AsyncTask may in fact be enough (I would put that in a separate class file though so it's reusable). The downside of this approach is, that since you only start asking for locations once you enter the Map view, it may take a moment to obtain a viable location.

answered Jun 2, 2017 at 1:01
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.