Android GraphView Realtime app lags
Asked Answered
E

0

7

I'm using GraphView in Android to plot realtime data (ECG), received from Bluetooth (BLE) connected sensor.

After a while (5-10 sec = 500-1000 points) the application becomes extremely slow and laggy.

The output data rate of the sensor is 100Hz and the data are received and plotted as soon as they are generated (every 10ms).

As indicated in similar occasions, I keep only the data I need to display. I tried minimizing the view (2 sec = 200 points), testing the app in different Android devices, but the problem insists. Any ideas?

import com.jjoe64.graphview.GraphView;
import com.jjoe64.graphview.series.DataPoint;
import com.jjoe64.graphview.series.LineGraphSeries;
import com.jjoe64.graphview.GridLabelRenderer;

...

//GraphView init
static LinearLayout GraphView1;
static GraphView graphView1;
static LineGraphSeries<DataPoint> Series1;

static LinearLayout GraphView2;
static GraphView graphView2;
static LineGraphSeries<DataPoint> Series2;

static LinearLayout GraphView3;
static GraphView graphView3;
static LineGraphSeries<DataPoint> Series3;

private static int Xview = 5;
private static int maxpoints = 500;
private static double xstep = 0.01d;
private static double graph2LastXValue = 0;
static boolean AutoScrollX = true;

Initialize Graphview for channel 1 (init_ch2() and init_ch3() similarly):

void init_ch1(){
    GraphView1 = (LinearLayout) findViewById(R.id.Channel1);
    Series1 = new LineGraphSeries<DataPoint>(new DataPoint[] {new DataPoint(0, 0)});
    graphView1 = new GraphView(this);

    graphView1.getViewport().setYAxisBoundsManual(Yview_manual);
    graphView1.getViewport().setMinX(0);
    graphView1.getViewport().setMaxX(Xview);
    graphView1.getViewport().setScrollable(true);
    graphView1.getViewport().setScalable(true);
    graphView1.getGridLabelRenderer().setGridStyle(GridLabelRenderer.GridStyle.BOTH);
    graphView1.getGridLabelRenderer().setGridColor(Color.DKGRAY);
    graphView1.getGridLabelRenderer().setHorizontalLabelsVisible(false);
    graphView1.getGridLabelRenderer().setVerticalLabelsVisible(true);
    graphView1.getGridLabelRenderer().setNumHorizontalLabels(6);
    graphView1.getGridLabelRenderer().setNumVerticalLabels(3);
    graphView1.getGridLabelRenderer().setVerticalLabelsColor(Color.WHITE);
    graphView1.getGridLabelRenderer().reloadStyles();

    Series1.setThickness(6);
    Series1.setColor(Color.GREEN);

    graphView1.addSeries(Series1); // data
    GraphView1.addView(graphView1);
}

Callback called when new data are received:

public void updateECGCals(BluetoothGattCharacteristic characteristic) {
    Integer data1, data2, data3;

    data1 = ReceiveChannelData(characteristic, i*CH_DATA_SIZE);
    data2 = ReceiveChannelData(characteristic, i*CH_DATA_SIZE+3);
    data3 = ReceiveChannelData(characteristic, i*CH_DATA_SIZE+6);
    String strIncom1 = Integer.toString(data1);      // create string from bytes array
    String strIncom2 = Integer.toString(data2);      // create string from bytes array
    String strIncom3 = Integer.toString(data3);      // create string from bytes array

    Series1.appendData(new DataPoint(graph2LastXValue,Double.parseDouble(strIncom1)),AutoScrollX,maxpoints);
    Series2.appendData(new DataPoint(graph2LastXValue,Double.parseDouble(strIncom2)),AutoScrollX,maxpoints);
    Series3.appendData(new DataPoint(graph2LastXValue,Double.parseDouble(strIncom3)),AutoScrollX,maxpoints);

    //X-axis control
    if (graph2LastXValue >= Xview) {
        Series1.resetData(new DataPoint[]{});
        Series2.resetData(new DataPoint[]{});
        Series3.resetData(new DataPoint[]{});
        graph2LastXValue = 0;
    } else graph2LastXValue += xstep;

    graphView1.getViewport().setMinX(0);
    graphView1.getViewport().setMaxX(Xview);
    graphView2.getViewport().setMinX(0);
    graphView2.getViewport().setMaxX(Xview);
    graphView3.getViewport().setMinX(0);
    graphView3.getViewport().setMaxX(Xview);

}

private static Integer ReceiveChannelData(BluetoothGattCharacteristic c, int offset) {
    Integer output_code;

    Integer MSByte = c.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset);
    Integer MDByte = c.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset+1);
    Integer LSByte = c.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset+2);

    output_code = (MSByte << 16) + (MDByte << 8) + LSByte;

    return output_code;
}
Edina answered 26/5, 2015 at 0:39 Comment(5)
While it might be the all of the objects you are creating in updateECGCals, I don't know so I recommend putting your app through a performance profile. Not sure if you've seen Google's videos on Android Performance Patterns: youtube.com/playlist?list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCEBreezy
Thank you for the link. According to GPU rendering, my app has very big both Update and Execute time. Considering that these depend on the library's functions, I cannot do anything. Or not? Could I improve the code ?Edina
I've also tried using appendData() but it's terrible performance with multiple series. I then decided that I'd use a Queue: when new data arrives, pop the data from the head and push the new value to the tail. It's better performance, but still choppy.Gosling
did you found any solution ?Horatio
Same problem here. Even worse, after some time, my UI hangs. I do put appendData in a Runnable thread.Fyke

© 2022 - 2024 — McMap. All rights reserved.