본문 바로가기
카테고리 없음

MAUI BTLE InTheHand Client Sample. part2

by leo21c 2025. 10. 16.

Sample 코드 테스트 한 결과 Connect 이후에 Disconnect를 하고 다시 Connect를 하면 연결이 되지 않고 아래와 같은 예외가 발생했다.

{"Cannot access a disposed object."}

 

발생 원인을 확인한 결과 아래와 같은 이유가 있었다.


이 문제는 일반적으로 한 번 연결이 해제된 블루투스 장치 객체(Object)를 다시 사용하려고 할 때 발생합니다.

InTheHand.Bluetooth 라이브러리에서는 Gatt.Disconnect()가 호출되면 내부적으로 장치 객체의 일부 리소스가 해제(Dispose)됩니다. 따라서 동일한 객체로 다시 연결을 시도하면 이미 해제된 리소스에 접근하게 되어 예외가 발생하는 것입니다.

원인 설명

  1. 최초 연결: DeviceListViewModel의 ToggleConnect 메서드에서 BtleDeviceItem에 포함된 BluetoothDevice 객체를 사용하여 장치에 연결합니다.
  2. 연결 해제: GlobalData._ClientConnect.Disconnect()가 호출되면, 현재 연결에 사용된 BluetoothDevice 객체와 관련된 내부 리소스(GATT 서버 등)가 해제됩니다.
  3. 재연결 시도: 사용자가 다시 'Connect' 버튼을 누르면, Devices 컬렉션에 저장되어 있던 기존 BtleDeviceItem 객체를 그대로 사용합니다. 이 객체는 이미 리소스가 해제된 BluetoothDevice 인스턴스를 참조하고 있습니다.
  4. 예외 발생: 해제된 BluetoothDevice 객체를 사용하여 ConnectToDevice()를 호출하면, .NET 런타임은 이미 메모리에서 정리된 객체에 접근하려 하기 때문에 ObjectDisposedException ("Cannot access a disposed object.")을 발생시킵니다.

해결책

이 문제를 해결하려면, 연결 해제 후 다시 연결을 시도할 때 새로운 BluetoothDevice 객체를 가져와야 합니다. BluetoothDevice.GetDeviceByIdAsync 메서드를 사용하여 장치의 고유 ID로 새로운 객체를 얻어온 후 연결을 시도하는 방식으로 코드를 수정할 수 있습니다.


[수정전]

[RelayCommand]
private async Task ConnectToDevice(BtleDeviceItem item)
{
    StopScan();

    if (_connectedServer != null && _connectedServer.IsConnected)
    {
        _connectedServer.Disconnect();
        CleanUpConnection();
    }

    try
    {
        ConnectionStatus = $"Connecting to {item.Device.Name}...";
        _connectedServer = item.Device.Gatt;

        // Await the connection task. If it fails, it will throw an exception.
        await _connectedServer.ConnectAsync();

        // If we get here, the connection was successful.
        if (_connectedServer.IsConnected)
        {
            ConnectionStatus = "Connected";
            await SetupCharacteristics();
        }
        else
        {
            throw new Exception("Failed to connect to the device.");
        }
    }
    catch (Exception ex)
    {
        ConnectionStatus = $"Connection Failed: {ex.Message}";
        CleanUpConnection();
    }
}

Connect를 할 때 기존 item.Device를 그래도 사용한다.
이 부분이 문제이다. Disconnect를 하면 인스턴스가 해제 되기 때문에 그대로 사용하면 연결이 되지 않는 것이다.

 

[수정후]

try
{
    ConnectionStatus = $"Connecting to {item.Device.Name}...";

    // Get a new device object instance by its ID to avoid using a disposed object.
    var device = await BluetoothDevice.FromIdAsync(item.Id);
    _connectedServer = device.Gatt;

 

그래서 위와 같이 item.Id를 가지고 BluetoothDevice 객체를 다시 가져와서 연결을 해야 한다.
var device = await BluetoothDevice.FromIdAsync(item.Id);

LIST