Android API级别15上的SurfaceView线程中出现意外的NullPointerException
我已经编写了一个应用程序,我想在更高的API级别上进行测试,以检查兼容性。对于API 10(2.3.3),没有问题,但当我在API 15(4.0.3)上运行我的应用程序时,当我退出活动时,我的一个SurfaceView中出现了NullPointerException。 我不得不说我解决了这个问题,但我不明白为什么会发生异常。也许你可以告诉我 以下是在API 10上为我工作的代码: 这是Android API级别15上的SurfaceView线程中出现意外的NullPointerException,android,multithreading,surfaceview,Android,Multithreading,Surfaceview,我已经编写了一个应用程序,我想在更高的API级别上进行测试,以检查兼容性。对于API 10(2.3.3),没有问题,但当我在API 15(4.0.3)上运行我的应用程序时,当我退出活动时,我的一个SurfaceView中出现了NullPointerException。 我不得不说我解决了这个问题,但我不明白为什么会发生异常。也许你可以告诉我 以下是在API 10上为我工作的代码: 这是run()-方法的常见结构 public void run() { while (mThreadActi
run()
-方法的常见结构
public void run() {
while (mThreadActive) {
c = null;
try {
c = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder) {
if(mState == 1) {
updateValues();
updateAnimation();
}
doDraw(c);
}
} finally {
if (c != null) {
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
在API 15上退出活动时:
当doDraw()
-方法试图在“c”上写入时出现异常。我检查了c,发现它是空的,所以毫不奇怪我得到了一个异常。我还检查了mThreadActive
,发现尽管我将其设置为false,但while
-循环仍然会触发。
以下是代码示例:
public void run() {
while (mThreadActive) {
c = null;
try {
c = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder) {
if(mState == 1) {
updateValues();
updateAnimation();
}
if(!mThreadActive) // so it really is!
Log.d("Thread", "mThreadActive is false!");
if(c == null) // so it is too!
Log.d("Thread", "c is null!");
doDraw(c); // error
}
} finally {
if (c != null) {
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
我可以想象为什么mThreadActive
在被while
-语句检查后变为false,但我无法理解为什么在mSurfaceHolder.lockCanvas(null)
之后“c”为null。代码似乎不是按顺序运行的
好的,解决方法是检查c!=在其上绘图之前为空:
public void run() {
while (mThreadActive) {
c = null;
try {
c = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder) {
if(mState == 1) {
updateValues();
updateAnimation();
}
if(c != null) // prevent drawing on c if c doesnt exist.
doDraw(c);
}
} finally {
if (c != null) {
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
那么,为什么在API 15上会出现异常,而在API 10上却可以正常工作呢?
另一件有趣的事是,我有其他具有相同结构的SurfaceView,但与此相比,它们都工作得很好!
为什么代码不是按顺序运行的?是不是因为我在一个模拟器上进行测试(这是相当滞后的)
谢谢。您提到,尽管mThreadActive
为false,您的while()
循环似乎仍在继续。mThreadActive
是否标记为volatile
?可能需要这样做
另外,lockCanvas(null)
。因为我们看不到您的代码的其余部分,所以不清楚您想做什么。API对将null
传入lockCanvas
有何说明?(我们谈论的是SurfaceHolder
的原始实例还是子类?)
请注意,的API规范指示它可以返回null
:
如果尚未创建曲面或无法编辑曲面,则返回null。通常需要实现Callback.surfaceCreated,以确定曲面何时可用
通过阅读API,您似乎应该实现接口并响应事件,这实际上是告诉您准备好写入画布的事件。调用时,我也遇到了一个非常类似的问题:
public void surfaceDestroyed(SurfaceHolder holder) {
isAttached = false;
this.drawthread = null;
}
退出应用程序以停止绘图线程时-我使用的while布尔值isAttached
为false,但该while循环中的绘图代码仍在执行-退出时出现nullexception。不是一个表演的停止者,而是一些我真的想要修复的东西。我也在考虑一种if(canvas!=null)
的解决方案,但我认为一定有更好的方法
现在,这个错误有一个奇怪的地方——它只在某些时候发生——在速度更快的设备上发生得更少。我所看到的问题是,holder.lockCanvas()
返回null,这意味着在布尔值设置为false之前,holder将被销毁,而while有机会停止执行线程。线程竞争问题
找到了一个可能的解决方案,该解决方案在使while布尔值为null之前使用了Thread.join()
,但是holder.lockCanvas()
返回null时,holder在绘图完成之前被销毁,因此它有点毫无意义,仍然会导致null异常
我能想到的唯一其他解决方案是重写back按钮方法,并在销毁surfaceview(如果是poss)之前强制while bool为null,但我认为if(canvas!=null)
可能更干净。还有什么其他的想法渴望听到吗
编辑:没有在其他地方测试过,但是我使用API 17得到错误,你能发布实际的异常跟踪吗?相关?lockCanvas()
中的null
对我的代码没有任何意义。我现在把它掉了。它应该是lockCanvas(Rect dirty)
。我已经实现了SurfaceHolder.Callback
接口。在surfaceCreated()。紧接着,我激活(mThreadActive=true)并启动线程(run()
)。我还将mThreadActive
标记为volatile。似乎while()
不再继续,但不知何故c仍然被调用并抛出其异常。也许它是从以前的while迭代调用的?