Я занимаюсь разработкой мобильного приложения с использованием Xamarin.Forms.Приложение подключается к устройству BLE, которое передает 16 байтов данных каждые 100 мс.Я строю данные с помощью Syncfusion в формате гистограммы.
Я могу подключиться к устройству и получать данные без проблем.Но через очень короткое время приложение начинает значительно снижать производительность.Вскоре после этого он полностью останавливается.Очевидно, я делаю что-то не так при обработке входящих данных (если только это не является проблемой производительности с диаграммой Syncfusion).
В двух словах, это процесс, который я прохожу в приложении
- Сопряжение с устройством (вне приложения)
- Подключение к устройству (в приложении)
- Настройка передачи
- Обработка входящих данных с помощью
Model
под названием SpectrogramModel - График данных с помощью Syncfusion в
View
, называемом DataPage, который связан с ViewModel
, называемым DataViewModel
.все, после сопряжения и подключения к устройству вызывается следующий метод.Может ли это быть вызов Device.BeginInvokeOnMainThread()
, который в конечном итоге начинает блокировать приложение?Этот метод вызывается из Connection
класса, который имеет ссылку на DataViewModel
private void UpdateSpectrogramChart(object sender, EventArgs e)
{
DebugHelper.Message(Type.Method, "UpdateSpectrogramChart");
_characteristic.ValueUpdated += (o, args) =>
{
var raw = args.Characteristic.Value;
for (int i = 0; i < raw.Length; i++)
{
Debug.WriteLine("Level[{0}] = {1}", i, raw[i]);
}
Xamarin.Forms.Device.BeginInvokeOnMainThread(() =>
{
DataPageViewModel.Levels.Clear();
for (int i = SpectrogramModel.FrequencyOffset; i < raw.Length; i++)
{
if (SettingsViewModel.IsViewRawData)
{
DataPageViewModel.Title = "Raw data";
DataPageViewModel
.Levels
.Add(
new SpectrogramModel(
raw[i],
1 + (i - SpectrogramModel.FrequencyOffset))
);
}
if (SettingsViewModel.IsViewProcessedData)
{
DataPageViewModel.Title = "Processed data";
DataPageViewModel
.Levels
.Add(
new SpectrogramModel(
raw[i],
1 + (i - SpectrogramModel.FrequencyOffset),
i));
}
}
});
};
}
SpectrogramModel выглядит следующим образом
public class SpectrogramModel
{
public SpectrogramModel(byte level, int frequency)
{
Level = level;
Frequency = frequency;
}
public SpectrogramModel(byte level, int frequency, int index) : this(level, frequency)
{
Level = ProcessRawLevel(level, index);
}
private double ProcessRawLevel(byte b, int index)
{
double multiplier = 0.75;
double val = b;
val *= multiplier;
return val;
}
public static readonly int FrequencyOffset = 4;
...
DataPage выглядит следующим образом
<chart:SfChart>
<chart:SfChart.Title>
<chart:ChartTitle
Text="{Binding Title}">
</chart:ChartTitle>
</chart:SfChart.Title>
<chart:SfChart.PrimaryAxis>
<chart:CategoryAxis>
</chart:CategoryAxis>
</chart:SfChart.PrimaryAxis>
<chart:SfChart.SecondaryAxis>
<chart:NumericalAxis
Minimum="20"
Maximum="100">
</chart:NumericalAxis>
</chart:SfChart.SecondaryAxis>
<chart:SfChart.Series>
<chart:ColumnSeries ItemsSource="{Binding Levels}" XBindingPath="Frequency" YBindingPath="Level"/>
</chart:SfChart.Series>
</chart:SfChart>
Наконец, DataViewModel, к которому привязан DataPage
public class DataViewModel : BaseViewModel
{
public DataViewModel()
{
Init();
}
private void Init()
{
Levels = new ObservableCollection<SpectrogramModel>();
for (int i = 0; i < 16; i++) Levels.Add(new SpectrogramModel(20, i));
}
private ObservableCollection<SpectrogramModel> _levels;
public ObservableCollection<SpectrogramModel> Levels
{
get { return _levels; ; }
set
{
_levels = value;
OnPropertyChanged();
}
}
private string _title;
public string Title
{
get { return _title; }
set
{
_title = value;
OnPropertyChanged();
}
}
}
Следует отметить, что UpdateSpectrogramChart()
обернут в таймер, который выглядит следующим образом
public void InitTimers()
{
DebugHelper.Message(Type.Method, "InitTimers");
int SECOND = 1000 * 2;
SpectrogramChartTimer = new Timer();
SpectrogramChartTimer.Elapsed += new ElapsedEventHandler(UpdateSpectrogramChart);
SpectrogramChartTimer.Interval = SECOND;
}
Я обернул вызов метода UpdateSpectrogramChart()
в (сбрасывать) неудачную попытку уменьшить снижение производительности.
Для полноты, вот тело метода, которое устанавливает прием от устройства BLE
public async Task ReceiveFromGattCharacteristic(string service, string characteristic, string descriptor = null)
{
DebugHelper.Message(Type.Method, "ReceiveFromGattCharacteristic");
bleAdapter.DeviceConnected += async (s, e) =>
{
try
{
DebugHelper.Message(Type.Info, "bleAdapter.DeviceConected += async (s, e) ...");
string[] deviceInfo = { e.Device.Name, e.Device.Id.ToString() };
// Connect to service
try
{
DebugHelper.Message(Type.Info, "Connecting to service...");
_service = await e.Device.GetServiceAsync(Guid.Parse(service));
DebugHelper.Message(Type.Info, "OK");
}
catch (Exception)
{
DebugHelper.Error(ErrorType.GATT, "Could not connect to service");
}
// Connect to characteristic
try
{
DebugHelper.Message(Type.Info, "Connecting to characteristic...");
_characteristic = await _service.GetCharacteristicAsync(Guid.Parse(characteristic));
DebugHelper.Message(Type.Info, "OK");
}
catch (Exception)
{
DebugHelper.Error(ErrorType.GATT, "Could not connect to characteristic");
}
await ConfigureSpectrogram(UpdateFrequency.High, 0x1);
try
{
await _characteristic.StartUpdatesAsync();
}
catch
{
DebugHelper.Error(ErrorType.GATT, "Error starting UpdatesAsync");
}
_characteristic.ValueUpdated += (o, args) =>
{
var raw = args.Characteristic.Value;
for (int i = 4; i < raw.Length; i++)
{
Debug.WriteLine("Level[{0}] = {1}", i - 4, raw[i]);
}
};
}
catch (Exception)
{
DebugHelper.Error(ErrorType.GATT, "Error in ReceiveFromGattCharacteristic");
}
};
}