javaandroidmultithreadingreal-timeandroid-graphview

Android Real Time Graph app crashing. Possible multi-threading issue


I'm having a problem with a college project in which I need to display real-time readings from an arduino on an android device. The arduino and Bluetooth link are working fine. On the android side, I start a new thread to retrieve these values and add them to an arraylist FullSignal.

    private synchronized void theloop(){
    AsyncTask.execute(new Runnable() {
        @Override
        public void run() {
            try
            {
                while(btSocket.isConnected() ){
                    if(!pause) {
                        BufferedReader r = new BufferedReader(new InputStreamReader(btSocket.getInputStream()));
                        String total = "";
                        String line;

                        if ((line = r.readLine()) != null) {
                            total = (line);
                        }
                        if (!total.equals("")) {
                            double xtoadd = ((new Date().getTime()) - startOfRun) / 1000;
                            DataPoint dp = new DataPoint(xtoadd, Double.parseDouble(total));
                            FullSignal.add(dp);
                            sleep(10);
                        }
                    }
                    else{
                        sleep(10);

This thread is doing what I want and puts the readings into the arraylist, (the time they arrive, and the value). Then I have another thread which calls an Update_Graph method every 50ms, and passes in the current FullSignal arraylist.

    private synchronized void Update_Graph_loop() {
    Thread thread = new Thread()
    {
        @Override
        public void run() {
            try {
                while(!ending) {
                    if(!pause){
                        Update_Graph(FullSignal);
                        sleep(50);
                    }
                    else{
                        sleep(50);
                    }
                }
            } catch (InterruptedException e) {
                Toast.makeText(getBaseContext(), e.toString(), Toast.LENGTH_LONG).show();
            }
        }
    };

    thread.start();
}

The Update_Graph it calls, does some maths to get the the graph displaying the values which were read from the arduino and when they arrived.

    private synchronized void Update_Graph(ArrayList<DataPoint> FS)
{

    graph = (GraphView) findViewById(R.id.graph);
    series = new LineGraphSeries<DataPoint>();

    for (int i = dpToDisp.length - 1; i >= 0; i--) {
        DataPoint dp = FS.get(FS.size() - (dpToDisp.length - i));
        dpToDisp[i] = new DataPoint(((dp.getX() * 1000 + startOfRun) - (new Date().getTime())) / 1000, dp.getY());
    }

    series.resetData(dpToDisp);
    series.setThickness(20);
    series.setColor(Color.RED);
    graph.removeAllSeries();
    graph.addSeries(series);
}

The app behaves exactly as I want it to for a while (Usually between 5 - 25 secs) and then crashes. Screenshot of app running before crash

The console shows a Null Object Reference error but doesn't show the line of my code causing it.

    E/AndroidRuntime: FATAL EXCEPTION: main
              Process: app.stephen.com.samsungs2test, PID: 28668
              java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.Integer.intValue()' on a null object reference
                  at com.jjoe64.graphview.GridLabelRenderer.drawVerticalSteps(GridLabelRenderer.java:1302)
                  at com.jjoe64.graphview.GridLabelRenderer.draw(GridLabelRenderer.java:1071)
                  at com.jjoe64.graphview.GraphView.drawGraphElements(GraphView.java:299)
                  at com.jjoe64.graphview.GridLabelRenderer.draw(GridLabelRenderer.java:1062)
                  at com.jjoe64.graphview.GraphView.drawGraphElements(GraphView.java:299)
                  at com.jjoe64.graphview.GraphView.onDraw(GraphView.java:323)
                  at android.view.View.draw(View.java:16068)

The way it crashes does not seem to be dependent on time or a memory problem, which makes me think that it is a multi-threading issue.

I have made all my methods private and synchronized. Is there any other steps I can make to make my program thread safe? Or can anyone see where the problem might be arising?


Solution

  • I don't have a solution but here's a few random thoughts:

    2 possible causes:

    a) GraphView has a reference to an object you passed to it and you are modifying that object while the View is drawing

    b) This is not a thread synchronization issue, you've just passed some corrupted data to GraphView, somehow

    if the problem is a), could try this:

    instead of calling methods on GraphView from other threads, post a runnable on it so it will run on the UI thread

    graph.post(new Runnable(){
        @Override
        public void run(){
            graph.removeAllSeries();
            graph.addSeries(series);        
        }
    });