Android Real Time Graph应用程序崩溃。可能的多线程问题

时间:2017-03-10 12:41:15

标签: java android multithreading real-time android-graphview

我在大学项目中遇到问题,我需要在Android设备上显示来自arduino的实时读数。 arduino和蓝牙链接工作正常。在android方面,我启动一个新线程来检索这些值并将它们添加到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);

这个线程正在做我想要的事情并将读数放入arraylist(它们到达的时间和值)。然后我有另一个每50ms调用一次Update_Graph方法的线程,并传入当前的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();
}

它调用的Update_Graph会做一些数学运算,让图表显示从arduino读取的值以及它们何时到达。

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

应用程序的行为与我想要的一段时间(通常在5 - 25秒之间)然后崩溃。 Screenshot of app running before crash

控制台显示Null Object Reference错误,但没有显示导致它的代码行。

    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)

崩溃的方式似乎并不依赖于时间或内存问题,这让我觉得这是一个多线程的问题。

我已将所有方法设为私有和同步。我可以做任何其他步骤来使我的程序线程安全吗?或者任何人都可以看到问题可能出现在哪里?

1 个答案:

答案 0 :(得分:1)

有一个解决方案,但这里有一些随意的想法:

  • 我认为你误解了synchronized方法的含义,至少从你如何使用它来Update_Graph_loop
  • 来自堆栈跟踪的
  • 看起来像是在GraphView.onDraw方法中取消装箱整数的空引用,该方法在UI线程上运行,将synchronized关键字添加到方法不会阻止GraphView.onDraw访问您在已同步的方法中使用的对象
  • 我唯一看到你传递给GraphView的是LineGraphSeries,也许这就是问题的根源

2个可能的原因:

a)GraphView引用了您传递给它的对象,并且在View正在绘制时正在修改该对象

b)这不是线程同步问题,您只是将一些损坏的数据传递给GraphView,不知何故

如果问题是a),可以试试这个:

而不是从其他线程调用GraphView上的方法,在其上发布一个runnable,以便它将在UI线程上运行

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