Android 实时图表应用崩溃。可能的多线程问题

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

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

这个线程正在做我想做的,并将读数放入数组列表(它们到达的时间和值)。然后我有另一个线程每 50 毫秒调用一个 Update_Graph 方法,并传入当前的 FullSignal 数组列表。

    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)

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

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

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

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

2 个可能的原因:

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

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

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

不是从其他线程调用 GraphView 上的方法,而是 post 在其上启用 运行,这样它将 运行 在 UI 线程上

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

我遇到了类似的问题,实际上我已经将代码放入 runnable() UI 线程中。 如下,我的代码:

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

你怎么看?