长时间连续扫描蓝牙时出现内存泄漏

时间:2019-06-30 23:54:11

标签: c# android memory-leaks bluetooth android-bluetooth

我有一个需要无限期扫描蓝牙设备的应用程序。因此,我的用例是我扫描蓝牙设备5秒钟,获取所有广告数据,延迟1秒钟,然后再次重复扫描。我的代码可以在大约7-8小时(有时超过24小时)内完美运行,然后运行到内存泄漏错误。

public class BLEScan:IBLEScan
{
    private CancellationTokenSource _scanCancellationToken;
    private volatile bool _IsScanning;
    public int ScanTimeout { get; set; } = 5000;
    public bool IsScanning
    {
        get { return _IsScanning; }
        private set { _IsScanning = value; }
    };

    private readonly BluetoothManager _bluetoothManager;
    private readonly BluetoothAdapter _bluetoothAdapter;

    private readonly Api21BleScanCallback _api21ScanCallback;
    private PendingIntent pendingIntent;

    public BLEScan()
    {
        _bluetoothManager = (BluetoothManager)Android.App.Application.Context.GetSystemService(Android.Content.Context.BluetoothService);
        _bluetoothAdapter = _bluetoothManager.Adapter;

        if (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop)
        {
            _api21ScanCallback = new Api21BleScanCallback();
        }
    }

    public async Task StartScanning(CancellationToken cancellationToken)
    {
        if (IsScanning)
        {
            Console.WriteLine("Scan Already Running.");
            return;
        }

        IsScanning = true;
        _scanCancellationToken = new CancellationTokenSource();
        try
        {
            using (cancellationToken.Register(() => _scanCancellationToken?.Cancel()))
            {
                await StartScanNative();
                await Task.Delay(ScanTimeout, _scanCancellationToken.Token);
                CleanUpScan();
            }
        }
        catch
        {

        }
    }

    public void CleanUpScan()
    {
        StopScanNative();

        if (_scanCancellationToken != null)
        {
            _scanCancellationToken.Dispose();
            _scanCancellationToken = null;
        }
        IsScanning = false;
    }

    public void StopScanNative()
    {
        if (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop)
        {
            _bluetoothAdapter.BluetoothLeScanner?.StopScan(pendingIntent);
        }
    }

    public Task StartScanNative()
    {
        if (Build.VERSION.SdkInt > BuildVersionCodes.Lollipop)
        {
            Intent receiverIntent = new Intent(Application.Context, typeof(Api21BleScanCallback));
            receiverIntent.SetAction("com.company.ACTION_FOUND");
            pendingIntent = PendingIntent.GetBroadcast(Application.Context, 1, receiverIntent, PendingIntentFlags.UpdateCurrent);
            _bluetoothAdapter.BluetoothLeScanner.StartScan(null, null, pendingIntent);
        }
        return Task.FromResult(true);
    }

    [BroadcastReceiver]
    [IntentFilter(new[] { "com.company.ACTION_FOUND" })]
    public class Api21BleScanCallback : BroadcastReceiver
    {
        public override void OnReceive(Context context, Intent intent)
        {
            var action = intent.Action;
            if (intent.HasExtra(BluetoothLeScanner.ExtraListScanResult))
            {
                var x = intent.GetParcelableArrayListExtra(BluetoothLeScanner.ExtraListScanResult);
              // Parse necessary data here 
            }
         }
    }
    }

  public interface IBLEScan
{
    int ScanTimeout { get; set; }
    bool IsScanning { get;}
    Task StartScanning(CancellationToken cancellationToken = default(CancellationToken));
}

我不确定哪个对象导致此错误。我已经在服务中实现了扫描,并且仍然存在相同的错误。扫描本身在任务中运行,并且BLEscan对象被延迟初始化。

 public async override void OnCreate()
    {
        base.OnCreate();
        var adapter = LazyPodScanner.Current;
        var task = Task.Run(async () =>
        {
            while (!cancellationTokenSource.IsCancellationRequested)
            {
                await adapter.StartScanning(cancellationTokenSource.Token);
                await Task.Delay(1000);
            }
        }, cancellationTokenSource.Token);
    }

此外,有时它还会遇到全局引用表溢出错误。

惰性初始化BLE扫描的实现:

 public class LazyPodScanner
{
    static readonly Lazy<IBLEScan> Implementation = new Lazy<IBLEScan>(CreateImplementation, System.Threading.LazyThreadSafetyMode.PublicationOnly);

    static IBLEScan CreateImplementation()
    {
        return new BLEScan();
    }

    public static IBLEScan Current
    {
        get
        {
            var val = Implementation.Value;
            if (val == null)
            {
                throw NotImplementedInReferenceAssembly();
            }
            return val;
        }
    }

    internal static Exception NotImplementedInReferenceAssembly()
    {
        return new NotImplementedException("Lazy Initialization of Scanner failed");
    }

}

0 个答案:

没有答案