我有一个需要无限期扫描蓝牙设备的应用程序。因此,我的用例是我扫描蓝牙设备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");
}
}