我正在使用Xamarin.Forms开发移动应用程序。该应用程序连接到BLE设备,该设备每100 ms发送一次16字节的数据。我正在用条形图格式的Syncfusion绘制数据。
我可以连接到设备并接收数据而不会出现问题。但是经过很短的时间后,该应用程序的性能开始显着下降。此后不久,它完全停滞了。显然,我在处理传入数据时做错了事(除非Syncfusion图表存在性能问题)。
简而言之,这是我在应用程序中经历的过程
Model
处理传入的数据View
的名为DataPage的ViewModel
中使用Syncfusion绘制数据,该数据绑定到名为DataViewModel的Device.BeginInvokeOnMainThread()
配对并连接到设备后,进入所有细节,调用以下方法。可能是Connection
调用最终开始阻止该应用程序吗?从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));
}
}
});
};
}
类中调用此方法,该类具有对DataViewModel的引用
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;
...
SpectrogramModel看起来像这样
<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>
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();
}
}
}
最后,绑定了DataPage的DataViewModel
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()
我以明显的失败尝试包装了对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");
}
};
}
方法的调用,以减少性能下降。
为完整性起见,这是设置从BLE设备接收的方法的方法主体
<?php if($_SESSION['username']!='info') echo 'hidden' ?>
答案 0 :(得分:0)
好吧,我不确定这个真的是否可以作为答案,但我似乎已经解决了这个问题,尽管我不能肯定地说为什么可以解决。
在摆弄BackgroundWorker
之后,引入了更多错误(可能是因为我对它的使用不熟悉),我修改了代码,并移动了Model
和{将{1}}直接添加到View
方法中,而不是通过单独的方法来更新ReceiveFromGattCharacteristic()
和Model
,如下所示:
View
答案 1 :(得分:0)
我们想让您知道,在使用大量数据并提高性能时,需要考虑一些SfChart配置。
我们可以阻止图表针对项源集合中的每次修改进行更新。通过使用SuspendSeriesNotification和ResumeSeriesNotification方法。
Xamarin.Forms.Device.BeginInvokeOnMainThread(() =>
{
DataPageViewModel.Levels.Clear();
Chart.SuspendSeriesNotification();
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));
}
}
Chart.ResumeSeriesNotification();
});
我们发现您正在使用带有列系列的“类别”轴。我们始终建议将数字或日期时间轴与快速线系列一起使用,以获得更好的性能。如果您确实需要类别轴和列系列,请让我们知道您的图表将加载多少数据或使用类别轴的任何原因。
从SfChart获得更好性能的一些技巧,请阅读以下博客。 https://blog.syncfusion.com/post/7-tips-to-optimize-xamarin-charts-performance.aspx#comment-10677
关于, 巴拉提。