java - Android速度BufferedReader读取行和ArrayList添加和获取

标签 java android arraylist opengl-es-2.0 bufferedreader

我创建了一个 Obj 文件读取器,它使用缓冲读取器逐行读取,我必须检查每一行是否是一个顶点,我将其添加到顶点ArrayList,如果它是一个面,我创建一个 Face 对象,其中 get(i) 顶点 ArrayList 和另外 2 个列表“法线和 UV”,然后添加到面列表中。 这是代码

public final void ctreateObject() {
    float now = System.nanoTime();  
    BufferedReader bufferReader = new BufferedReader(inputStreamReader);
    String line;
    try {
        while ((line = bufferReader.readLine()) != null) {              
            if (line.startsWith("f")) {
                processFLine(line);
            } else if (line.startsWith("vn")) {
                processVNLine(line);
            } else if (line.startsWith("vt")) {
                processVTLine(line);
            } else if (line.startsWith("v")) {
                processVLine(line);
            } else if (line.startsWith("usemtl")) {
                mtlName = line.split("[ ]+", 2)[1];
            } else if (line.startsWith("mtllib")) {
                mtllib = line.split("[ ]+")[1];
            } else if (line.startsWith("g") || line.startsWith("o")) {
                if (faces.size() > 0) {
                    List<Face> theFaces = new ArrayList<Face>();
                    theFaces.addAll(faces);
                    Model model = new Model(id, theFaces, mtlName);
                    SharedData.models.add(model);
                    faces.clear();
                }
            }
            Log.i("line", line);
            ln++;
        }
        if (faces.size() > 0) {
            List<Face> theFaces = new ArrayList<Face>();
            theFaces.addAll(faces);
            Model model = new Model(id, theFaces, mtlName);
            SharedData.models.add(model);
            faces.clear();
            vertices.clear();
            normals.clear();
            uvs.clear();
        }
        inputStreamReader.close();
        bufferReader.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    Log.i("Line", String.valueOf(ln));
    Log.i("time", String.valueOf((System.nanoTime() - now) / 1000000000));
}

private void processVLine(String line) {
    String[] tokens = line.split("[ ]+");
    vertices.add(new float[] { Float.parseFloat(tokens[1]), Float.parseFloat(tokens[2]), Float.parseFloat(tokens[3]) });
}

private void processVNLine(String line) {
    String[] tokens = line.split("[ ]+");
    normals.add(new float[] { Float.parseFloat(tokens[1]), Float.parseFloat(tokens[2]), Float.parseFloat(tokens[3]) });
}

private void processVTLine(String line) {
    String[] tokens = line.split("[ ]+");
    uvs.add(new float[] { Float.parseFloat(tokens[1]), Float.parseFloat(tokens[2]) });
}

private void processFLine(String line) {
    String[] tokens = line.split("[ ]+");
    if (tokens.length == 4) {
        makeFace3(tokens);
    }
}

private void makeFace3(String[] tokens) {
    if (tokens[1].matches("[0-9]+")) {// f: v
        Face face = new Face(vertices.get(Integer.parseInt(tokens[1]) - 1), vertices.get(Integer.parseInt(tokens[2]) - 1), vertices.get(Integer.parseInt(tokens[1]) - 1));
        if (normals.size() > 0) {
            face.setAn(normals.get(Integer.parseInt(tokens[1]) - 1));
            face.setBn(normals.get(Integer.parseInt(tokens[2]) - 1));
            face.setCn(normals.get(Integer.parseInt(tokens[3]) - 1));
        }
        if (uvs.size() > 0) {
            face.setAuv(uvs.get(Integer.parseInt(tokens[1]) - 1));
            face.setBuv(uvs.get(Integer.parseInt(tokens[2]) - 1));
            face.setCuv(uvs.get(Integer.parseInt(tokens[3]) - 1));
        }
        faces.add(face);
    }
    if (tokens[1].matches("[0-9]+/[0-9]+")) {
        Face face = new Face(vertices.get(Integer.parseInt(tokens[1].split("/")[0]) - 1), vertices.get(Integer.parseInt(tokens[2].split("/")[0]) - 1), vertices.get(Integer.parseInt(tokens[3].split("/")[0]) - 1));
        if (normals.size() > 0) {
            face.setAn(normals.get(Integer.parseInt(tokens[1].split("/")[0]) - 1));
            face.setBn(normals.get(Integer.parseInt(tokens[2].split("/")[0]) - 1));
            face.setCn(normals.get(Integer.parseInt(tokens[3].split("/")[0]) - 1));
        }
        if (uvs.size() > 0) {
            face.setAuv(uvs.get(Integer.parseInt(tokens[1].split("/")[1]) - 1));
            face.setBuv(uvs.get(Integer.parseInt(tokens[2].split("/")[1]) - 1));
            face.setCuv(uvs.get(Integer.parseInt(tokens[3].split("/")[1]) - 1));
        }
        faces.add(face);
    }
    if (tokens[1].matches("[0-9]+//[0-9]+")) {// f: v//vn
        Face face = new Face(vertices.get(Integer.parseInt(tokens[1].split("/")[0]) - 1), vertices.get(Integer.parseInt(tokens[2].split("/")[0]) - 1), vertices.get(Integer.parseInt(tokens[3].split("/")[0]) - 1));
        if (uvs.size() > 0) {
            face.setAuv(uvs.get(Integer.parseInt(tokens[1].split("/")[0]) - 1));
            face.setBuv(uvs.get(Integer.parseInt(tokens[2].split("/")[0]) - 1));
            face.setCuv(uvs.get(Integer.parseInt(tokens[3].split("/")[0]) - 1));
        }
        if (normals.size() > 0) {
            face.setAn(normals.get(Integer.parseInt(tokens[1].split("/")[2]) - 1));
            face.setBn(normals.get(Integer.parseInt(tokens[2].split("/")[2]) - 1));
            face.setCn(normals.get(Integer.parseInt(tokens[3].split("/")[2]) - 1));
        }
        faces.add(face);
    }
    if (tokens[1].matches("[0-9]+/[0-9]+/[0-9]+")) {
        Face face = new Face(vertices.get(Integer.parseInt(tokens[1].split("/")[0]) - 1), vertices.get(Integer.parseInt(tokens[2].split("/")[0]) - 1), vertices.get(Integer.parseInt(tokens[3].split("/")[0]) - 1));
        if (uvs.size() > 0) {
            face.setAuv(uvs.get(Integer.parseInt(tokens[1].split("/")[1]) - 1));
            face.setBuv(uvs.get(Integer.parseInt(tokens[2].split("/")[1]) - 1));
            face.setCuv(uvs.get(Integer.parseInt(tokens[3].split("/")[1]) - 1));
        }
        if (normals.size() > 0) {
            face.setAn(normals.get(Integer.parseInt(tokens[1].split("/")[2]) - 1));
            face.setBn(normals.get(Integer.parseInt(tokens[2].split("/")[2]) - 1));
            face.setCn(normals.get(Integer.parseInt(tokens[3].split("/")[2]) - 1));
        }
        faces.add(face);
    }
}

问题在于性能,如果文件包含大约 120,000 行,这个过程大约需要 90 秒,这太长了,因为我想加载许多这样的模型,如果文件更复杂并且有 850,000 行,这个过程大约需要 280 秒不接受秒,BufferReader 可以非常快地扫描行,但 ArrayList 处理导致速度慢,我测试了 LinkedList 但结果很糟糕“慢了 5 倍”,那么有没有一种方法或其他解决方案可以用来做到这一点?后来我迭代面孔ArrayList来创建缓冲区并将其传递给OpenGL

编辑 我使用 Vector 与相同的 120,000 行文件,结果是 109 秒(比 ArrayList 增加了 20 秒)

最佳答案

BufferedReaderArrayList 不是问题。

您的性能问题基本上可以归结为两个问题:分配和解析。

解析 - 第一部分

    String[] tokens = line.split("[ ]+");

您正在使用正则表达式对字符串进行标记。这是将行分割成标记的最慢的方法。您可以通过自己迭代字符串并在执行过程中构建标记来加快速度。这是“唾手可得的果实”,微小的改变将为您带来巨大的加速。

    if (tokens[1].matches("[0-9]+")) {// f: v

再次使用正则表达式。这会减慢你的速度。

解析 - 第二部分

为什么要重新解析已经解析过的内容?

    Face face = new Face(vertices.get(Integer.parseInt(tokens[1]) - 1), vertices.get(Integer.parseInt(tokens[2]) - 1), vertices.get(Integer.parseInt(tokens[1]) - 1));
    if (normals.size() > 0) {
        face.setAn(normals.get(Integer.parseInt(tokens[1]) - 1));
        face.setBn(normals.get(Integer.parseInt(tokens[2]) - 1));
        face.setCn(normals.get(Integer.parseInt(tokens[3]) - 1));
    }

您正在重复调用Integer.parseInt(tokens[x]) - 1。您应该将结果放入 int 中并使用它。

分配

查看调用 new 运算符的次数。每个对象分配都会降低性能。查看循环中的每个 new 运算符并询问:有什么方法可以一次性完成所有这些操作吗?例如:每个顶点都是一个float[3]。您可以从 numVertices 的试用值开始,然后调用 new float[numVertices][3],而不是一遍又一遍地调用 new float[3] 就一次吗?这可能并非在所有情况下都可行,但您应该寻找机会减少调用。

与此相关的是ArrayList的使用。使用ArrayList来积累对象很容易,但是效率不是很高。请记住,每次数组达到最大值时,都必须分配一个新数组并将所有现有数据复制到其中。

OBJ 文件格式不是很友好,因为它会转储顶点、坐标、 vector 等,而不会预先给您提供要使用的计数,这在这里会非常有帮助。

关于java - Android速度BufferedReader读取行和ArrayList添加和获取,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40127726/

相关文章:

java - 在 arraylist<JPanel> 中添加 JPanel

java - 我应该注入(inject)每个类或特定类吗?

java - wordpress servlet 映射不工作

Java 对齐网格

android - TabLayout 隐藏/显示动画

Android,分享直接到 Gmail,跳过其他应用

java - 在 64 位 Eclipse 上使用 32 位 JRE

android - 如何从 ImageAdapter Grid View 类调暗 ImageView ?

java - 遍历 ArrayList - 不打印任何内容

java - 为什么我的 ArrayList 没有循环遍历所有值?