seg
seg

Reputation: 31

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?

Upvotes: 2

Views: 812

Answers (2)

valio
valio

Reputation: 33

I am facing up a similar problem and I have already actually put the code inside a runnable() UI thread. As following, my code:

runOnUiThread(new Runnable() {
@Override
public void run() {
    if (data[7]%plot_freq==0) { 
    series.appendData(new DataPoint(x, pitch_1),true,500); 
    Log.v("Plot 1","OK"); 
    } 
    if (data_2[7]%plot_freq==0) { 
    series_2.appendData(new DataPoint(x, pitch_2),true,500); 
    Log.v("Plot 2","OK"); 
    } 
    if (data_3[7]%plot_freq==0) { 
    series_3.appendData(new DataPoint(x, pitch_3),true,500); 
    Log.v("Plot 3","OK"); 
    }

What do you think?

Upvotes: 0

lelloman
lelloman

Reputation: 14173

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

  • I think you are misunderstanding the meaning of a synchronized method, at least from how you're using it for Update_Graph_loop
  • from the stacktrace it looks like a null reference to an Integer is being unboxed within GraphView.onDraw method, that method is run on the UI thread, adding synchronized keyword to a method won't prevent GraphView.onDraw to access an object that you're using inside the method you've synchronized
  • the only thing I see you're passing to the GraphView is a LineGraphSeries, maybe that's the source of the problem

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);        
    }
});

Upvotes: 2

Related Questions