随着图表更新,UI迅速变慢

时间:2019-05-10 08:05:38

标签: android xamarin.forms bluetooth-lowenergy syncfusion

我正在使用Xamarin.Forms开发移动应用程序。该应用程序连接到BLE设备,该设备每100 ms发送一次16字节的数据。我正在用条形图格式的Syncfusion绘制数据。

我可以连接到设备并接收数据而不会出现问题。但是经过很短的时间后,该应用程序的性能开始显着下降。此后不久,它完全停滞了。显然,我在处理传入数据时做错了事(除非Syncfusion图表存在性能问题)。

简而言之,这是我在应用程序中经历的过程

  1. 配对到设备(在应用程序外部)
  2. 连接到设备(在应用程序中)
  3. 设置变速器
  4. 通过名为SpectrogramModel的Model处理传入的数据
  5. 在名为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' ?>

2 个答案:

答案 0 :(得分:0)

好吧,我不确定这个真的是否可以作为答案,但我似乎已经解决了这个问题,尽管我不能肯定地说为什么可以解决。

在摆弄BackgroundWorker之后,引入了更多错误(可能是因为我对它的使用不熟悉),我修改了代码,并移动了Model和{将{1}}直接添加到View方法中,而不是通过单独的方法来更新ReceiveFromGattCharacteristic()Model,如下所示:

View

答案 1 :(得分:0)

我们想让您知道,在使用大量数据并提高性能时,需要考虑一些SfChart配置。

  1. 使用SuspendSeriesNotification和ResumeSeriesNoification。

我们可以阻止图表针对项源集合中的每次修改进行更新。通过使用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();
            });
  1. 避免使用类别轴。

我们发现您正在使用带有列系列的“类别”轴。我们始终建议将数字或日期时间轴与快速线系列一起使用,以获得更好的性能。如果您确实需要类别轴和列系列,请让我们知道您的图表将加载多少数据或使用类别轴的任何原因。

从SfChart获得更好性能的一些技巧,请阅读以下博客。 https://blog.syncfusion.com/post/7-tips-to-optimize-xamarin-charts-performance.aspx#comment-10677

关于, 巴拉提。