Hi
I have some Bluetooth Low Energy (BLE) code in a Xamarin.Android and Xamarin.iOS project. This performs all the work in my app, running as a Service in Android and as a background app in iOS. I need to get the ConnectionState information from this to any Xamarin.Forms UI that happens to be present.
Currently I use an interface for this thus:
public interface IBleComms
{
void ConnectToDevice(Guid DeviceGuid);
event EventHandler<BleConnectionState.ProteusConnectionStatus> ProteusConnectionStateChangedEvent;
BleConnectionState.ProteusConnectionStatus GetProteusConnectionState();
}
I implement the interface in my Xamarin.Android 'BleComms' class - snippet:
[assembly: Xamarin.Forms.Dependency(typeof(BleComms))]
namespace ProteusPatientApp.Droid
{
public class BleComms : IBleComms
{
private static IDevice ProteusDevice = null;
public Guid ProteusGuid { get; private set; } = Guid.Empty;
private static IBluetoothLE ble = null;
private static Plugin.BLE.Abstractions.Contracts.IAdapter adapter = null;
private BleConnectionState.ProteusConnectionStatus CurrentProteusConnectionState = BleConnectionState.ProteusConnectionStatus.Unknown;
#region Interface
public event EventHandler<BleConnectionState.ProteusConnectionStatus> ProteusConnectionStateChangedEvent;
public BleConnectionState.ProteusConnectionStatus GetProteusConnectionState() => CurrentProteusConnectionState;
public void UpdateProteusConnectionState(BleConnectionState.ProteusConnectionStatus state)
{
CurrentProteusConnectionState = state;
ProteusConnectionStateChangedEvent?.Invoke(this, state);
proteusConnectionStatusNotification.UpdateNotification(state);
}
public void ConnectToProteus(Guid proteusGuid)
{
SetProteusGuid(proteusGuid);
SetStoredProteusGuid(proteusGuid);
}
#endregion
public BleComms()
{
ble = CrossBluetoothLE.Current;
adapter = CrossBluetoothLE.Current.Adapter;
adapter.ScanMode = ScanMode.LowLatency;
adapter.ScanTimeout = 30000;
.........
.........
}
}
}
Methods within BleComms call UpdateProteusConnectionState, which in turn triggers an event 'ProteusConnectionStateChangedEvent' that my UI code subscribes to.
This class is instantiated once by my Android service when it starts:
public class ProteusService : Service
{
static readonly string TAG = "X:" + typeof(ProteusService).Name;
bool isStarted = false;
CancellationTokenSource _cts;
private static BleComms bleComms;
public override void OnCreate() { }
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
if (!isStarted)
{
bleComms = new BleComms();
isStarted = true;
}
return StartCommandResult.Sticky;
}
}
In my Xamarin.forms viewmodel code, I subscribe to the ProteusConnectionStateChangedEvent thus:
DependencyService.Get<IBleComms>().ProteusConnectionStateChangedEvent += ConnectionStateChanged;
//ConnectionStateChanged is a method that updates the UI
I connect to my device thus:
DependencyService.Get<IBleComms>().ConnectToProteus(ProteusGuid);
The code works, but my BleComms class it gets instantiated **TWICE **- once by the Android service and then once again, on the first call through from the dependency service.
What I want to do is to have the BleComms class instantiated **ONCE ** as a singleton by the Service when it starts up, and have the dependency service obtain the results from the pre-existing instance rather than creating a new instance of BleComms.
Currently to get this working, I had to make some stuff within BleComms static - I suspect this is not the right way to do this, but using the MessagingService for this seems a but crude also - especially when I add the rest of the code and have loads of textural messages flying about the place. I did move the interface implementation into its own class, but that made setting the ProteusConnectionStateChangedEvent difficult.
I am new to interfaces and Xamarin Architecture, if anyone has a better suggestion, I would be interested to hear it!
Nigel