Android动态壁纸Resize时Libgdx抛出Bad position 8/0异常求助
解决LibGDX Android动态壁纸Resize时的IllegalArgumentException: Bad position异常
我之前在开发LibGDX Android动态壁纸时也踩过这个坑!这个异常的核心原因是NIO Buffer被设置了非法的position值(比如你看到的8/0,意思是Buffer容量为0,但代码尝试把position设为8),通常和动态壁纸生命周期里的资源销毁、重建时机不匹配有关——毕竟壁纸的生命周期逻辑比普通LibGDX应用要复杂得多。
下面是我验证有效的几种解决方法:
1. 严格在Resize时销毁并重建GL资源
不要尝试复用旧的Mesh或VertexArray,因为Resize触发时,旧资源的尺寸已经和新的窗口不匹配,而且很可能已经处于无效状态。正确的做法是:
- 在
resize方法中先检查资源是否存在,若存在则调用dispose()释放,再重新创建适配新尺寸的资源 - 确保所有操作都在GL线程执行(动态壁纸的
resize默认在GL线程,但如果有异步逻辑一定要同步)
示例代码:
private Mesh wallpaperMesh; @Override public void resize(int width, int height) { // 先清理旧资源 if (wallpaperMesh != null) { wallpaperMesh.dispose(); wallpaperMesh = null; } // 重建适配新尺寸的Mesh int vertexCount = 4; // 比如一个全屏四边形的顶点数 int indexCount = 6; wallpaperMesh = new Mesh(true, vertexCount, indexCount, new VertexAttribute(VertexAttributes.Usage.Position, 3, "a_position"), new VertexAttribute(VertexAttributes.Usage.ColorPacked, 4, "a_color")); // 填充新的顶点数据(适配新宽高) float[] vertices = createFullscreenVertices(width, height); wallpaperMesh.setVertices(vertices); short[] indices = {0, 1, 2, 2, 3, 0}; wallpaperMesh.setIndices(indices); }
2. 在Render方法中增加资源有效性检查
Resize操作可能和Render操作存在时序冲突(比如系统回调延迟导致Render时资源还没重建完成),所以在调用mesh.render()前一定要检查资源状态:
@Override public void render(float delta) { Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); // 若资源未就绪,直接跳过本次渲染 if (wallpaperMesh == null) return; shaderProgram.begin(); wallpaperMesh.bind(shaderProgram); wallpaperMesh.render(GL20.GL_TRIANGLES); wallpaperMesh.unbind(shaderProgram); shaderProgram.end(); }
3. 处理GL上下文丢失的场景
Android系统会在内存紧张时回收壁纸的GL上下文,此时所有旧的GL资源(Mesh、Shader、Texture等)都会失效,即使没触发Resize也会抛出类似异常。要在resume方法中重建所有GL资源:
@Override public void resume() { // 上下文丢失后,所有GL资源都会变为null或无效 if (wallpaperMesh == null) { int currentWidth = Gdx.graphics.getWidth(); int currentHeight = Gdx.graphics.getHeight(); // 复用Resize的重建逻辑 resize(currentWidth, currentHeight); } // 同时重建Shader、Texture等其他GL资源 }
4. 规范NIO Buffer的操作
如果你手动操作FloatBuffer/ShortBuffer来填充顶点数据,一定要记得调用flip()方法重置Buffer的position和limit——这是很多开发者容易忽略的细节:
private float[] createFullscreenVertices(int width, int height) { float[] vertices = { 0, 0, 0, Color.WHITE.toFloatBits(), width, 0, 0, Color.WHITE.toFloatBits(), width, height, 0, Color.WHITE.toFloatBits(), 0, height, 0, Color.WHITE.toFloatBits() }; FloatBuffer buffer = BufferUtils.newFloatBuffer(vertices.length); buffer.put(vertices); buffer.flip(); // 关键:将limit设为当前position,position重置为0 return buffer.array(); }
调试小技巧
- 在
resize、dispose、resume方法中添加日志,跟踪资源销毁和重建的时机,看是否和Render操作冲突 - 用断点查看抛出异常时Buffer的
capacity()、position()、limit()值,定位是哪一步导致了非法的position设置
内容的提问来源于stack exchange,提问作者lacas
相关产品推荐
相关产品推荐

