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");
}
你怎么看?
我在大学项目中遇到问题,我需要在 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");
}
你怎么看?