停止线程不适用于函数 setRunning(false)
Stop thread is not working with function setRunning(false)
我有一个使用 canvas 画线的项目。我的项目(下载 here)将创建一个随机数并使用 canvas 在线连接它们。它运作良好。但问题是,当我的应用程序正在运行并且我单击主页按钮时,我的应用程序将崩溃,例如
FATAL EXCEPTION: Thread-10001
java.lang.NullPointerException
at com.example.waveplot.WaveformView.PlotPoints(WaveformView.java:78)
at com.example.waveplot.WaveformPlotThread.run(WaveformPlotThread.java:35)
如何解决?太感谢了。
让我解释一下我的申请。我的应用程序包括三个类:
WaveformView.java: class to draw the line in thread with random number.
MainActivity.java: main calss and create the random number and call WaveformView class
WaveformPlotThread: create a thread and manager canvas
这是我的代码
MainActivity.java
private Runnable Timer_Tick = new Runnable() {
public void run() {
numRandom=genNum(0,200)-100;// from -100 to 100
if(dataIndex1<MAX_SAMPLES)
dataY[dataIndex1++] = numRandom;
else
{
dataY[MAX_SAMPLES-1] = numRandom;
for (int i = 0; i < WIDTH/10 - 1; i++)
//Shift data
dataY[i]=dataY[i+1];
}
mWaveform.set_data(dataY);
}
};
WaveformView.java
public class WaveformView extends SurfaceView implements SurfaceHolder.Callback{
// plot area size
private final static int WIDTH = 660;
private static int[] dataX = new int[WIDTH];
private static int[] dataY = new int[WIDTH];
private WaveformPlotThread plot_thread;
private Paint dataY_color = new Paint();
private int index = 0;
public WaveformView(Context context, AttributeSet attrs){
super(context, attrs);
getHolder().addCallback(this);
plot_thread = new WaveformPlotThread(getHolder(), this);
dataY_color.setColor(Color.GREEN);
dataY_color.setStrokeWidth(3);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height){
}
@Override
public void surfaceCreated(SurfaceHolder holder){
plot_thread.setRunning(true);
plot_thread.start();
//plot_thread.startThread();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder){
Log.d("D","STOOOOOOOOOOOOOOOOOOP");
boolean retry = true;
plot_thread.setRunning(false);
while (retry){
try{
plot_thread.join();
retry = false;
}catch(InterruptedException e){
}
}
}
@Override
public void onDraw(Canvas canvas){
PlotPoints(canvas);
}
public void set_data(int[] data1){
plot_thread.setRunning(false);
if(index<WIDTH/10-1)
index++;
for(int x=0; x<WIDTH/10-1; x++){
if(x<(data1.length)){
dataX[x+1]=(x+1)*WIDTH/66;
dataY[x] = data1[x];
}
else{
dataY[x] = 0;
}
}
plot_thread.setRunning(true);
}
public void PlotPoints(Canvas canvas){
if(canvas == null) { return ; }
// clear screen
canvas.drawColor(Color.rgb(20, 20, 20));
// plot data
for(int x=0; x<index-1; x++){
canvas.drawLine(dataX[x], dataY[x], dataX[x+1], dataY[x+1], dataY_color);
}
}
}
WaveformPlotThread
public class WaveformPlotThread extends Thread {
private SurfaceHolder holder;
private WaveformView plot_area;
// private volatile Thread runner;
private volatile boolean _run=true;
public WaveformPlotThread(SurfaceHolder surfaceHolder, WaveformView view){
holder = surfaceHolder;
plot_area = view;
}
public void setRunning(boolean run){
_run = run;
}
@Override
public void run(){
Canvas c;
while(_run){
//while(Thread.currentThread() == runner){
c = null;
try{
c = holder.lockCanvas(null);
synchronized (holder) {
plot_area.PlotPoints(c);
}
}finally{
if(c!=null){
holder.unlockCanvasAndPost(c);
}
}
}
}
}
这是日志文件
D/D(9747): STOOOOOOOOOOOOOOOOOOP
W/SurfaceView(9747): CHECK surface infomation creating=false formatChanged=false sizeChanged=false visible=false visibleChanged=true surfaceChanged=true realSizeChanged=false redrawNeeded=false left=false top=false
W/System.err(9747): java.lang.IllegalThreadStateException: Thread already started.
W/System.err(9747): at java.lang.Thread.start(Thread.java:1045)
W/System.err(9747): at com.example.waveplot.WaveformView.surfaceCreated(WaveformView.java:41)
W/System.err(9747): at android.view.SurfaceView.updateWindow(SurfaceView.java:609)
W/System.err(9747): at android.view.SurfaceView.onWindowVisibilityChanged(SurfaceView.java:235)
W/System.err(9747): at android.view.View.dispatchWindowVisibilityChanged(View.java:7625)
W/System.err(9747): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1047)
W/System.err(9747): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1047)
W/System.err(9747): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1047)
W/System.err(9747): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1047)
W/System.err(9747): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1047)
W/System.err(9747): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1047)
W/System.err(9747): at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1346)
W/System.err(9747): at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1121)
W/System.err(9747): at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4598)
W/System.err(9747): at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725)
W/System.err(9747): at android.view.Choreographer.doCallbacks(Choreographer.java:555)
W/System.err(9747): at android.view.Choreographer.doFrame(Choreographer.java:525)
W/System.err(9747): at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711)
W/System.err(9747): at android.os.Handler.handleCallback(Handler.java:615)
W/System.err(9747): at android.os.Handler.dispatchMessage(Handler.java:92)
W/System.err(9747): at android.os.Looper.loop(Looper.java:137)
W/System.err(9747): at android.app.ActivityThread.main(ActivityThread.java:4950)
W/System.err(9747): at java.lang.reflect.Method.invokeNative(Native Method)
W/System.err(9747): at java.lang.reflect.Method.invoke(Method.java:511)
W/System.err(9747): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:997)
W/System.err(9747): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:764)
W/System.err(9747): at dalvik.system.NativeStart.main(Native Method)
解决:根据Veritas的建议,我把创建新线程的函数放到了SurfaceCreated
@Override
public void surfaceCreated(SurfaceHolder holder){
plot_thread = new WaveformPlotThread(getHolder(), this);
plot_thread.setRunning(true);
plot_thread.start();
}
public WaveformView(Context context, AttributeSet attrs){
super(context, attrs);
getHolder().addCallback(this);
//plot_thread = new WaveformPlotThread(getHolder(), this);
dataY_color.setColor(Color.GREEN);
dataY_color.setStrokeWidth(3);
}
使 _run
可变,因此读取和写入是原子的。参见 http://docs.oracle.com/javase/tutorial/essential/concurrency/atomic.html
public class WaveformPlotThread extends Thread {
private SurfaceHolder holder;
private WaveformView plot_area;
private volatile boolean _run = false;
四件事
检查 PlotPoints 方法中的 canvas 是否为空,
if(canvas == null) {
return; // return 静默
}
可能在 surface 上被破坏的 surfaceholder return给你一个 null canvas
正如 isalgueiro 所建议的那样,将 _运行 设为 volatile/
将_运行的默认值设置为true,因为如果你在某个地方开始这个线程而没有将_运行设置为true,线程很可能会在之前结束你可以用它做任何有建设性的事情。默认值 false 在您的情况下没有任何意义。
不要扩展线程而是实现 运行nable。
最后两点是更多的最佳实践..
--编辑--
目前在 surfaceCreated 中创建一个新线程然后启动它,这是因为当 _运行 设置为 false 时退出 while 循环的逻辑将使线程完成其 运行 方法并且线程将死。该错误是自我指示的,一旦线程已经启动,您就无法启动它。您可以通过更正 _运行 = false/true 的逻辑来重用您的线程,或者通过使用 Executor ThreadPool 来采用更好的解决方案,请参阅 http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html。
暂时你可以在 surfacecreated 方法中创建一个新线程而不是构造函数
我运行陷入了同样的问题。我无法弄清楚为什么 Thread
在调用 setRunning(false)
时不会停止,但我设法通过将 plot_area.PlotPoints()
包装在另一个 if(canvas != null)
语句中来绕过 NullPointerException
.因此 WaveformPlotThread
中的 run()
方法将如下所示:
@Override
public void run(){
Canvas c;
while(_run){
//while(Thread.currentThread() == runner){
c = null;
try{
c = holder.lockCanvas(null);
synchronized (holder) {
if(c!=null) {
plot_area.PlotPoints(c);
}
}
}finally{
if(c!=null){
holder.unlockCanvasAndPost(c);
}
}
}
}
此外,作为旁注,@Override public void onDraw(Canvas canvas)
不是必需的,并且不建议覆盖 onDraw()
或 draw()
。可以删除整个方法。
我有一个使用 canvas 画线的项目。我的项目(下载 here)将创建一个随机数并使用 canvas 在线连接它们。它运作良好。但问题是,当我的应用程序正在运行并且我单击主页按钮时,我的应用程序将崩溃,例如
FATAL EXCEPTION: Thread-10001
java.lang.NullPointerException
at com.example.waveplot.WaveformView.PlotPoints(WaveformView.java:78)
at com.example.waveplot.WaveformPlotThread.run(WaveformPlotThread.java:35)
如何解决?太感谢了。 让我解释一下我的申请。我的应用程序包括三个类:
WaveformView.java: class to draw the line in thread with random number.
MainActivity.java: main calss and create the random number and call WaveformView class
WaveformPlotThread: create a thread and manager canvas
这是我的代码 MainActivity.java
private Runnable Timer_Tick = new Runnable() {
public void run() {
numRandom=genNum(0,200)-100;// from -100 to 100
if(dataIndex1<MAX_SAMPLES)
dataY[dataIndex1++] = numRandom;
else
{
dataY[MAX_SAMPLES-1] = numRandom;
for (int i = 0; i < WIDTH/10 - 1; i++)
//Shift data
dataY[i]=dataY[i+1];
}
mWaveform.set_data(dataY);
}
};
WaveformView.java
public class WaveformView extends SurfaceView implements SurfaceHolder.Callback{
// plot area size
private final static int WIDTH = 660;
private static int[] dataX = new int[WIDTH];
private static int[] dataY = new int[WIDTH];
private WaveformPlotThread plot_thread;
private Paint dataY_color = new Paint();
private int index = 0;
public WaveformView(Context context, AttributeSet attrs){
super(context, attrs);
getHolder().addCallback(this);
plot_thread = new WaveformPlotThread(getHolder(), this);
dataY_color.setColor(Color.GREEN);
dataY_color.setStrokeWidth(3);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height){
}
@Override
public void surfaceCreated(SurfaceHolder holder){
plot_thread.setRunning(true);
plot_thread.start();
//plot_thread.startThread();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder){
Log.d("D","STOOOOOOOOOOOOOOOOOOP");
boolean retry = true;
plot_thread.setRunning(false);
while (retry){
try{
plot_thread.join();
retry = false;
}catch(InterruptedException e){
}
}
}
@Override
public void onDraw(Canvas canvas){
PlotPoints(canvas);
}
public void set_data(int[] data1){
plot_thread.setRunning(false);
if(index<WIDTH/10-1)
index++;
for(int x=0; x<WIDTH/10-1; x++){
if(x<(data1.length)){
dataX[x+1]=(x+1)*WIDTH/66;
dataY[x] = data1[x];
}
else{
dataY[x] = 0;
}
}
plot_thread.setRunning(true);
}
public void PlotPoints(Canvas canvas){
if(canvas == null) { return ; }
// clear screen
canvas.drawColor(Color.rgb(20, 20, 20));
// plot data
for(int x=0; x<index-1; x++){
canvas.drawLine(dataX[x], dataY[x], dataX[x+1], dataY[x+1], dataY_color);
}
}
}
WaveformPlotThread
public class WaveformPlotThread extends Thread {
private SurfaceHolder holder;
private WaveformView plot_area;
// private volatile Thread runner;
private volatile boolean _run=true;
public WaveformPlotThread(SurfaceHolder surfaceHolder, WaveformView view){
holder = surfaceHolder;
plot_area = view;
}
public void setRunning(boolean run){
_run = run;
}
@Override
public void run(){
Canvas c;
while(_run){
//while(Thread.currentThread() == runner){
c = null;
try{
c = holder.lockCanvas(null);
synchronized (holder) {
plot_area.PlotPoints(c);
}
}finally{
if(c!=null){
holder.unlockCanvasAndPost(c);
}
}
}
}
}
这是日志文件
D/D(9747): STOOOOOOOOOOOOOOOOOOP
W/SurfaceView(9747): CHECK surface infomation creating=false formatChanged=false sizeChanged=false visible=false visibleChanged=true surfaceChanged=true realSizeChanged=false redrawNeeded=false left=false top=false
W/System.err(9747): java.lang.IllegalThreadStateException: Thread already started.
W/System.err(9747): at java.lang.Thread.start(Thread.java:1045)
W/System.err(9747): at com.example.waveplot.WaveformView.surfaceCreated(WaveformView.java:41)
W/System.err(9747): at android.view.SurfaceView.updateWindow(SurfaceView.java:609)
W/System.err(9747): at android.view.SurfaceView.onWindowVisibilityChanged(SurfaceView.java:235)
W/System.err(9747): at android.view.View.dispatchWindowVisibilityChanged(View.java:7625)
W/System.err(9747): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1047)
W/System.err(9747): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1047)
W/System.err(9747): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1047)
W/System.err(9747): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1047)
W/System.err(9747): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1047)
W/System.err(9747): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1047)
W/System.err(9747): at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1346)
W/System.err(9747): at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1121)
W/System.err(9747): at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4598)
W/System.err(9747): at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725)
W/System.err(9747): at android.view.Choreographer.doCallbacks(Choreographer.java:555)
W/System.err(9747): at android.view.Choreographer.doFrame(Choreographer.java:525)
W/System.err(9747): at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711)
W/System.err(9747): at android.os.Handler.handleCallback(Handler.java:615)
W/System.err(9747): at android.os.Handler.dispatchMessage(Handler.java:92)
W/System.err(9747): at android.os.Looper.loop(Looper.java:137)
W/System.err(9747): at android.app.ActivityThread.main(ActivityThread.java:4950)
W/System.err(9747): at java.lang.reflect.Method.invokeNative(Native Method)
W/System.err(9747): at java.lang.reflect.Method.invoke(Method.java:511)
W/System.err(9747): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:997)
W/System.err(9747): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:764)
W/System.err(9747): at dalvik.system.NativeStart.main(Native Method)
解决:根据Veritas的建议,我把创建新线程的函数放到了SurfaceCreated
@Override
public void surfaceCreated(SurfaceHolder holder){
plot_thread = new WaveformPlotThread(getHolder(), this);
plot_thread.setRunning(true);
plot_thread.start();
}
public WaveformView(Context context, AttributeSet attrs){
super(context, attrs);
getHolder().addCallback(this);
//plot_thread = new WaveformPlotThread(getHolder(), this);
dataY_color.setColor(Color.GREEN);
dataY_color.setStrokeWidth(3);
}
使 _run
可变,因此读取和写入是原子的。参见 http://docs.oracle.com/javase/tutorial/essential/concurrency/atomic.html
public class WaveformPlotThread extends Thread {
private SurfaceHolder holder;
private WaveformView plot_area;
private volatile boolean _run = false;
四件事
检查 PlotPoints 方法中的 canvas 是否为空,
if(canvas == null) { return; // return 静默 }
可能在 surface 上被破坏的 surfaceholder return给你一个 null canvas
正如 isalgueiro 所建议的那样,将 _运行 设为 volatile/
将_运行的默认值设置为true,因为如果你在某个地方开始这个线程而没有将_运行设置为true,线程很可能会在之前结束你可以用它做任何有建设性的事情。默认值 false 在您的情况下没有任何意义。
不要扩展线程而是实现 运行nable。
最后两点是更多的最佳实践..
--编辑-- 目前在 surfaceCreated 中创建一个新线程然后启动它,这是因为当 _运行 设置为 false 时退出 while 循环的逻辑将使线程完成其 运行 方法并且线程将死。该错误是自我指示的,一旦线程已经启动,您就无法启动它。您可以通过更正 _运行 = false/true 的逻辑来重用您的线程,或者通过使用 Executor ThreadPool 来采用更好的解决方案,请参阅 http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html。 暂时你可以在 surfacecreated 方法中创建一个新线程而不是构造函数
我运行陷入了同样的问题。我无法弄清楚为什么 Thread
在调用 setRunning(false)
时不会停止,但我设法通过将 plot_area.PlotPoints()
包装在另一个 if(canvas != null)
语句中来绕过 NullPointerException
.因此 WaveformPlotThread
中的 run()
方法将如下所示:
@Override
public void run(){
Canvas c;
while(_run){
//while(Thread.currentThread() == runner){
c = null;
try{
c = holder.lockCanvas(null);
synchronized (holder) {
if(c!=null) {
plot_area.PlotPoints(c);
}
}
}finally{
if(c!=null){
holder.unlockCanvasAndPost(c);
}
}
}
}
此外,作为旁注,@Override public void onDraw(Canvas canvas)
不是必需的,并且不建议覆盖 onDraw()
或 draw()
。可以删除整个方法。