2016-10-01 1 views
3

私はScichartを使ってアンドロイド用のリアルタイムグラフ作成アプリを書いています。私は私のデータ系列SciChart Androidリアルタイムグラフ:グラフ作成の速度を最大限にするには?

のラッパーとして

FastLineRenderableSeriesを使用してきた。しかし、私はグラフの速度を最大にするために存在するのAndroid SciChartと、他のどのような技術を思ったんだけど?

特に、私はIXyDataSeriesを使用し、x軸のサイズを10,000から100,000ポイントに増やすとパフォーマンスが低下していることに気付きました。私のIXyDataSeriesに約90,000ポイントを追加するまで、グラフの速度は一貫して速くなります。

ありがとうございます。私はスタックオーバーフローに新しいです... CSの人よりもmechEの詳細。

ここに私のgraphFragmentクラスがあります。これは、UDPセンサーデータを文字列として取り込み、スプライスしてIXyDataSeriesに追加します。

public class GraphFragment extends Fragment { 

    //Various fields... 
    //UDP Settings 
    private UdpClient client; 
    private String hostname; 
    private int remotePort; 
    private int localPort; 

    //Use to communicate with UDPDataClass 
    private Handler handler; 

    private boolean listenerExists = false; 
    private int xBound = 100000; //**Graphing Slows if xBound is TOO large** 
    private int yBound = 5000; 
    private boolean applyBeenPressed = false; 

    private GraphDataSource dataSource; //Gets data from UDPDataClass 
    private SciChartSurface plotSurface; //Graphing Surface 
    protected final SciChartBuilder sciChartBuilder = SciChartBuilder.instance(); 

    //Data Series containers 
    //Perhaps it would be better to use XyySeries here? 
    private final IXyDataSeries<Double, Double> dataSeriesSensor1 = sciChartBuilder.newXyDataSeries(Double.class, Double.class).build(); 
    private final IXyDataSeries<Double, Double> dataSeriesSensor2 = sciChartBuilder.newXyDataSeries(Double.class, Double.class).build(); 
    private final IXyDataSeries<Double, Double> dataSeriesSensor3 = sciChartBuilder.newXyDataSeries(Double.class, Double.class).build(); 
    private final IXyDataSeries<Double, Double> dataSeriesSensor4 = sciChartBuilder.newXyDataSeries(Double.class, Double.class).build(); 
    private final IXyDataSeries<Double, Double> dataSeriesSensor5 = sciChartBuilder.newXyDataSeries(Double.class, Double.class).build(); 
    private final IXyDataSeries<Double, Double> dataSeriesSensor6 = sciChartBuilder.newXyDataSeries(Double.class, Double.class).build(); 
    private ArrayList<IXyDataSeries<Double,Double>> dataSeriesList = new ArrayList<>(Arrays.asList(dataSeriesSensor1,dataSeriesSensor2,dataSeriesSensor3,dataSeriesSensor4, dataSeriesSensor5, dataSeriesSensor6)); 
    private ArrayList<Double> xCounters = new ArrayList<>(Arrays.asList(0.0,0.0,0.0,0.0,0.0,0.0)); 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
    final View frag = inflater.inflate(R.layout.graph_fragment, container, false); 

    plotSurface = (SciChartSurface) frag.findViewById(R.id.dynamic_plot); 

    dataSource = new GraphDataSource(); //Run the data handling on a separate thread 
    dataSource.start(); 

    UpdateSuspender.using(plotSurface, new Runnable() { 
     @Override 
     public void run() { 
      final NumericAxis xAxis = sciChartBuilder.newNumericAxis().withVisibleRange(0,xBound).build(); 
      final NumericAxis yAxis = sciChartBuilder.newNumericAxis().withVisibleRange(0,yBound).build(); 

      //These are wrappers for the series we will add the data to...It contains the formatting 
      final FastLineRenderableSeries rs1 = sciChartBuilder.newLineSeries().withDataSeries(dataSeriesSensor1).withStrokeStyle(ColorUtil.argb(0xFF, 0x40, 0x83, 0xB7)).build(); //Light Blue Color 
      final FastLineRenderableSeries rs2 = sciChartBuilder.newLineSeries().withDataSeries(dataSeriesSensor2).withStrokeStyle(ColorUtil.argb(0xFF, 0xFF, 0xA5, 0x00)).build(); //Light Pink Color 
      final FastLineRenderableSeries rs3 = sciChartBuilder.newLineSeries().withDataSeries(dataSeriesSensor3).withStrokeStyle(ColorUtil.argb(0xFF, 0xE1, 0x32, 0x19)).build(); //Orange Red Color 
      final FastLineRenderableSeries rs4 = sciChartBuilder.newLineSeries().withDataSeries(dataSeriesSensor4).withStrokeStyle(ColorUtil.argb(0xFF, 0xFF, 0xFF, 0xFF)).build(); //White color 
      final FastLineRenderableSeries rs5 = sciChartBuilder.newLineSeries().withDataSeries(dataSeriesSensor5).withStrokeStyle(ColorUtil.argb(0xFF, 0xFF, 0xFF, 0x99)).build(); //Light Yellow color 
      final FastLineRenderableSeries rs6 = sciChartBuilder.newLineSeries().withDataSeries(dataSeriesSensor6).withStrokeStyle(ColorUtil.argb(0xFF, 0xFF, 0x99, 0x33)).build(); //Light Orange color 

      Collections.addAll(plotSurface.getXAxes(), xAxis); 
      Collections.addAll(plotSurface.getYAxes(), yAxis); 
      Collections.addAll(plotSurface.getRenderableSeries(), rs1, rs2, rs3, rs4, rs5, rs6); 
     } 
    }); 

    return frag; 
    } 

//This class receives the UDP sensor data as messages to its handler 
//Then it splices the data 
//Adds the data to the IXySeries 
//Then the UpdateSuspender updates the graph 
//New data arrives approx every 50 ms (around 20x a second) 
//Graphing slows when xAxis is increased to ~100,000 
//X data is only counters...Only care about Y data 
public class GraphDataSource extends Thread{ 

    public void run(){ 
     Looper.prepare(); 
     //Get Data from UDP Data Class when its available 
     handler = new Handler(){ 
      public void handleMessage(Message msg){ 
       String sensorData = msg.getData().getString("data"); //Data receiveds 
       if(dataValid(sensorData)){ 
        sensorData = sensorData.replaceAll("\\s", ""); 
        final String[] dataSplit = sensorData.split(","); //split the data at the commas 

        UpdateSuspender.using(plotSurface, new Runnable() { //This updater graphs the values 
          @Override 
          public void run() { 
           spliceDataAndAddData(dataSplit); 
          } 
         }); 
       } 
      } 
     }; 
     Looper.loop(); 
    } 

    /** 
    * 
    * @param data string of the udp data 
    * @return true if the data isn't corrupted..aka the correct length 
    */ 
    private boolean dataValid(String data){ 
     return ((data.length() == 1350)); 
    } 

    /** 
    * 
    * @param dataSplit String[] of the entire data 
    * Adds the each sensor data to the IXySeries representing the data 
    */ 
    private void spliceDataAndAddData(String[] dataSplit){ 
     addToSensorSeries(dataSplit, 1); 
     addToSensorSeries(dataSplit, 2); 
     addToSensorSeries(dataSplit, 3); 
     addToSensorSeries(dataSplit, 4); 
     addToSensorSeries(dataSplit, 5); 
     addToSensorSeries(dataSplit, 6); 
    } 

    /** 
    * 
    * @param dataSplit data to split into individual sensor array 
    *     must contain only string representations of numbers 
    * @param sensorSeriesNumber which sensors to collect the data points of 
    * Adds the data to the corresponding IXySeries 
    */ 
    private void addToSensorSeries(String[] dataSplit, int sensorSeriesNumber){ 
     sensorSeriesNumber -= 1; //Adds each value individually to the series 
     double xcounter = xCounters.get(sensorSeriesNumber); 
     int i = sensorSeriesNumber; 
     int dataSize = dataSplit.length - 1; 
     String num = ""; 
     while(true){ 
      if(i < 6){ //This is the base case...add the first set of data 
       num = dataSplit[i]; 
       try { 
        if(xcounter > xBound){ 
         xcounter = 0; 
         dataSeriesList.get(sensorSeriesNumber).clear(); 
        } 
        dataSeriesList.get(sensorSeriesNumber).append(xcounter, Double.parseDouble(num)); //appends every number... 
       }catch (Exception e){ 
        //Corrupt data 
       } 
      }else if((i) <= dataSize && i >= 6){ //Will start to get hit after the second time 
       num = dataSplit[i]; 
       try { 
        if(xcounter > xBound){ 
         xcounter = 0; 
         dataSeriesList.get(sensorSeriesNumber).clear(); 
        } 
        dataSeriesList.get(sensorSeriesNumber).append(xcounter, Double.parseDouble(num)); 
       }catch (Exception e){ 
        //Corrupt data 
       } 
      }else{ 
       break; 
      } 
      xcounter++; 
      i += 6; 
     } 
     xCounters.set(sensorSeriesNumber,xcounter); 
    } 
} 
+0

通常、stackoverflowで質問するとき、人々があなたがすでに試したこと、問題の可能性が理解できるように、そしてそれがうまくいかなかった理由を特定できるように、コードサンプルを与えるのが慣例です。 –

+1

こんにちは@ Dr.ABTさん、お返事ありがとうございます。上記のコードサンプルを追加しました。パフォーマンスデモのアンドロイドの例から自分のコードを派生させようとしました。私はFastLineRenderableシリーズでIXyDataSeriesを使用しています。私はアンドロイドのHandler構造体を使用してフラグメントクラスにデータを読み込み、受け取ったデータをスプライシングしてからIXyDataSeriesに追加します。その後、私はUpdateSuspenderを使ってポイントを再配置します。グラフは、X軸のサイズを100,000ポイントに増やし、約90,000ポイントを追加した後にしか減速しなくなるまでうまく機能します。多くの人に役立つアイデアがある場合 – mmellor

+0

近代的なAndroidデバイスでは、チャートを100万ポイント程度テストしているので、それはちょっと奇妙です。質問:Androidのパフォーマンスデモは減速しますか? https://www.scichart.com/android-chart-realtime-performance-demo/ https://www.scichart.com/android-chart-loading-1-million-points-instantly-demo/こちらをご覧ください100kまたは1Mポイントをクリックして追加することができます –

答えて

4

私はあなたのコードを見て、私たちが何かできるかどうかは分かりません。あなたの例は0から100000までのXRangeを持つ6つのXyDataSeriesを含んでいます。これは、HTC Oneのリアルタイムの例ではかなり良い600,000点を画面に表示します。私は


SciChartのAndroidチームのリード開発者です。しかし、私は思う:SciChart性能のデモでは、各シリーズ

開示でより多くのポイントを描画することを可能にする唯一の3 XyDataSeriesインスタンスの使用状況を見ることができますコードにいくつかの最適化を追加することで、余分なFPSを少しでも得ることができます。リアルタイムチャートの主な問題は、グラフを更新するコードにあります。更新中にオブジェクトを作成して保存しないと、非常に頻繁に呼び出されますので、AndroidでGCが原因で問題が発生する可能性がありますGCがすべての未使用オブジェクトを収集している間に、すべてのアプリケーションのスレッドを一時停止することができます)。だから私は、あなたが次に何をすることをお勧め:

  • 私はあなたのaplicationでheap sizeを増やすことを示唆している:より多くのメモリアプリケーションが持っている - あなたが効率的にメモリを使用する場合、それは実行少ないGCを。
  • boxing/unboxingの量を減らし、frequntlyと呼ばれるコード(データシリーズの更新など)に少ないオブジェクトを割り当てるようにしてください。基本的には、データ系列を更新するコールバック内のオブジェクトの作成を忘れる必要があります。あなたのコードでは、ボクシング/アンボクシングが発生する場所はほとんど見つけられませんでした。このコードは、毎秒と呼ばれ、ボクシングの効果は/アンボクシングが大幅にアプリケーションのパフォーマンスに影響を及ぼすことができるように、いくつかの方法は、ループ内で呼び出されます。

dataSeriesList.get(sensorSeriesNumber).append(xcounter, Double.parseDouble(num));

double xcounter = xCounters.get(sensorSeriesNumber);

xCounters.set(sensorSeriesNumber,xcounter);

IをあなたはIValuesを受け入れるappend overrideを使うことを提案します。 IValuesを受け入れるappendを使用すると、たくさんのデータを非常に頻繁に追加するときに、不要なboxing/unboxingを避けることができます。

  • また、XyDataSeriesを作成するときにDoubleが本当に必要でない限り、FloatまたはIntegerを使用することをお勧めします。これにより、メモリ消費量を半分に減らすことができます(int/floatを格納するために2倍と4倍を格納するために8バイトを格納することができます)。結果アプリケーションにはGCを少なくするための空きメモリが多くなります。

希望すると、これが役立ちます。

+2

こんにちは!どうもありがとう!私はあなたのアドバイスを実装し、それぞれ100万ポイント(1百万!)の6つのセンサーのグラフをテストし、グラフは反応し続けるままでした!ありがとう!私はunboxingを修正し、追加オーバーライドを使用してそれが何をしたと思うが、私はあなたがしたすべての提案を実装しました。ありがとう! Scichartは素晴らしいです。 :) – mmellor

関連する問題