You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:41:25