我编写了一个应用程序,我想在更高的API级别上测试以检查兼容性。对于API 10(2.3.3)没有问题,但是当我在API 15(4.0.3)上运行我的应用程序时,当我退出Activity时,我的一个SurfaceViews中出现了NullPointerException。 我不得不说我解决了这个问题,但我无法弄清楚为什么实际发生了异常。所以也许你可以告诉我。
以下是在API 10上为我工作的代码:
这是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并发现它是null,所以毫不奇怪我得到了一个例外。我还检查了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
- 语句检查后变为假的原因,但我无法弄清楚为什么“{”在mSurfaceHolder.lockCanvas(null)
之后为空。似乎代码没有顺序运行。
嗯,解决方法是在绘制之前检查c != null
:
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上运行良好呢? 另一个有趣的是,我有其他具有相同结构的SurfaceViews,但与此相比,它们工作得很好! 为什么代码没有顺序运行?是因为我在模拟器上测试(这是非常迟钝的)?
谢谢。
答案 0 :(得分:2)
您提到尽管while()
为假,但您的mThreadActive
循环似乎仍在继续。 mThreadActive
是否已标记volatile
?它可能需要。
此外,lockCanvas(null)
闻起来。由于我们无法看到您的其余代码,因此您不清楚自己要做什么。 API如何将null
传递给lockCanvas
? (我们是在讨论SurfaceHolder
或子类的原始实例吗?)
请注意,SurfaceHolder.lockCanvas()
的API规范表明它可以返回null
:
如果尚未创建曲面或无法编辑曲面,则返回null。您通常需要实现Callback.surfaceCreated以找出Surface何时可用。
通过阅读API,看起来您应该实现SurfaceHolder.Callback
界面并回复surfaceCreated()
事件,这实际上是一个事件,告诉您已准备好写入画布。
答案 1 :(得分:0)
调用时我也遇到了类似的问题:
public void surfaceDestroyed(SurfaceHolder holder) {
isAttached = false;
this.drawthread = null;
}
当退出我的应用程序以停止绘制线程时 - 我使用isAttached
的while布尔值为false,但是while循环中的绘图代码仍然执行 - 在退出时给出了一个nullexception。不是一个显示塞子,但我真的想要修复。正在考虑if (canvas != null)
种解决方案,但我认为必须有更好的方法。
现在这里出现了这个错误的奇怪之处 - 它只在某些时候发生 - 并且在更快的设备上发生的情况更少。我看到的问题是holder.lockCanvas()
返回null - 意味着在boolean设置为false之前,holder被销毁,而while有机会停止执行Thread。线程竞赛问题?
在使while boolean null之前找到了一个使用Thread.join()
的可能解决方案,但是holder.lockCanvas()
返回null,在绘制完成之前,持有者被销毁,所以它有点无意义并且仍然导致一个nullexception。
我能想到的只有其他解决方案是覆盖后退按钮方法并在销毁surfaceview之前将while bool强制为null(如果可能的话),但我认为if (canvas != null)
可能更清晰。那里的任何其他想法都渴望听到!
编辑:尚未在其他地方测试,但我使用API 17
收到错误