Android 随着图表更新,用户界面速度迅速减慢
我正在使用Xamarin.Forms开发一个移动应用程序。该应用程序连接到一个BLE设备,该设备每100毫秒传输16字节的数据。我正在用Syncfusion以条形图格式绘制数据 我可以连接到设备并接收数据而不会出现问题。但在很短的时间内,应用程序的性能开始显著下降。很快,它就完全停止了。显然,我在处理传入数据时出错了(除非是Syncfusion图表的性能问题) 简而言之,这就是我在应用程序中经历的过程Android 随着图表更新,用户界面速度迅速减慢,android,xamarin.forms,bluetooth-lowenergy,syncfusion,Android,Xamarin.forms,Bluetooth Lowenergy,Syncfusion,我正在使用Xamarin.Forms开发一个移动应用程序。该应用程序连接到一个BLE设备,该设备每100毫秒传输16字节的数据。我正在用Syncfusion以条形图格式绘制数据 我可以连接到设备并接收数据而不会出现问题。但在很短的时间内,应用程序的性能开始显著下降。很快,它就完全停止了。显然,我在处理传入数据时出错了(除非是Syncfusion图表的性能问题) 简而言之,这就是我在应用程序中经历的过程 配对到设备(应用程序外部) 连接到设备(在应用程序中) 安装变速器 通过名为Spectrogr
模型处理传入数据
视图
中使用Syncfusion绘制数据图,该视图绑定到名为DataViewModel的视图模型
设备.beginInvokeMainThread()
调用最终开始阻止应用程序?此方法是从连接类调用的,该类引用了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));
}
}
});
};
}
数据页如下所示
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;
...
<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>
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");
}
};
}
公共异步任务ReceiveFromGattCharacteristic(字符串服务,字符串特征,字符串描述符=null)
{
Message(Type.Method,“ReceiveFromGattCharacteristic”);
bleAdapter.DeviceConnected+=异步(s,e)=>
{
尝试
{
消息(Type.Info,“bleAdapter.deviceconnected+=async(s,e)…”;
字符串[]deviceInfo={e.Device.Name,e.Device.Id.ToString()};
//连接到服务
尝试
{
消息(Type.Info,“连接到服务…”);
_service=wait e.Device.GetServiceAsync(Guid.Parse(service));
DebugHelper.Message(Type.Info,“OK”);
}
捕获(例外)
{
DebugHelper.Error(ErrorType.GATT,“无法连接到服务”);
}
//连接到特征
尝试
{
消息(Type.Info,“连接到特征…”);
_characteristic=wait_service.GetCharacteristicAsync(Guid.Parse(characteristic));
DebugHelper.Message(Type.Info,“OK”);
}
捕获(例外)
{
DebugHelper.Error(ErrorType.GATT,“无法连接到特征”);
}
等待配置频谱图(UpdateFrequency.High,0x1);
尝试
{
wait_characteristic.StartUpdatesAsync();
}
抓住
{
DebugHelper.Error(ErrorType.GATT,“启动更新同步时出错”);
}
_characteristic.ValueUpdated+=(o,args)=>
{
var raw=args.Characteristic.Value;
for(int i=4;i
好吧,我不确定这是否真的可以作为一个答案,但我似乎已经解决了这个问题,尽管我不能肯定这为什么解决了这个问题
在摆弄了一个BackgroundWorker
(可能是因为我不擅长使用它)之后,我修改了代码,并将模型的更新和视图的更新直接移动到ReceiveFromGattCharacteristic()
,方法,而不是使用单独的方法更新模型
和视图
,如下所示:
public void 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");
}
// ADDITION
_characteristic.ValueUpdated += (o, args) =>
{
var raw = args.Characteristic.Value;
Xamarin.Forms.Device.BeginInvokeOnMainThread(() =>
{
DataPageViewModel.Levels.Clear();
for (int i = Models.Spectrogram.FrequencyOffset; i < raw.Length; i++)
{
if (SettingsViewModel.IsViewRawData)
{
DataPageViewModel.Title = "Raw data";
DataPageViewModel
.Levels
.Add(
new Models.Spectrogram(
raw[i],
1 + (i - Models.Spectrogram.FrequencyOffset))
);
}
if (SettingsViewModel.IsViewProcessedData)
{
DataPageViewModel.Title = "Processed data";
DataPageViewModel
.Levels
.Add(
new Models.Spectrogram(
raw[i],
1 + (i - Models.Spectrogram.FrequencyOffset),
i));
}
}
});
};
}
// END OF ADDITION
catch (Exception)
{
DebugHelper.Error(ErrorType.GATT, "Error in ReceiveFromGattCharacteristic");
}
};
}
public void ReceiveFromGattCharacteristic(字符串服务,字符串特征,字符串描述符=null)
{
Message(Type.Method,“ReceiveFromGattCharacteristic”);
bleAdapter.DeviceConnected+=异步(s,e)=>
{
尝试
{
消息(Type.Info,“bleAdapter.deviceconnected+=async(s,e)…”;
字符串[]deviceInfo={e.Device.Name,e.Device.Id.ToString()};
//连接到服务
尝试
{
消息(Type.Info,“连接到服务…”);
_service=wait e.Device.GetServiceAsync(Guid.Parse(service));
DebugHelper.Message(Type.Info,“OK”);
}
捕获(例外)
{
DebugHelper.Error(ErrorType.GATT,“无法连接到服务”);
}
//连接到特征
尝试
{
消息(Type.Info,“连接到特征…”);
_characteristic=wait_service.GetCharacteristicAsync(Guid.Parse(characteristic));
DebugHelper.Message(Type.Info,“OK”);
}
捕获(例外)
{
DebugHelper.Error(ErrorType.GATT,“无法连接到特征”);
}
等待确认
public void 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");
}
// ADDITION
_characteristic.ValueUpdated += (o, args) =>
{
var raw = args.Characteristic.Value;
Xamarin.Forms.Device.BeginInvokeOnMainThread(() =>
{
DataPageViewModel.Levels.Clear();
for (int i = Models.Spectrogram.FrequencyOffset; i < raw.Length; i++)
{
if (SettingsViewModel.IsViewRawData)
{
DataPageViewModel.Title = "Raw data";
DataPageViewModel
.Levels
.Add(
new Models.Spectrogram(
raw[i],
1 + (i - Models.Spectrogram.FrequencyOffset))
);
}
if (SettingsViewModel.IsViewProcessedData)
{
DataPageViewModel.Title = "Processed data";
DataPageViewModel
.Levels
.Add(
new Models.Spectrogram(
raw[i],
1 + (i - Models.Spectrogram.FrequencyOffset),
i));
}
}
});
};
}
// END OF ADDITION
catch (Exception)
{
DebugHelper.Error(ErrorType.GATT, "Error in ReceiveFromGattCharacteristic");
}
};
}
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();
});