【问题标题】:Android speed issue with deserialization using SimpleXML使用 SimpleXML 反序列化的 Android 速度问题
【发布时间】:2013-04-02 00:29:54
【问题描述】:

提出赏金,因为唯一的答案没有为 Android 提供良好的实现。是否有更快的实现与 Android 兼容?还是 SimpleXML 是我能获得的最佳性能?

我对 Java 和 Android 开发相当陌生,所以不知道将 xml 字符串反序列化为对象的正确过程。我找到了一种适用于的方法:

public static Object deserializeXMLToObject(String xmlFile,Object objClass)  throws Exception 
{ 
    try
    {
            InputStream stream = new ByteArrayInputStream(xmlFile.getBytes("UTF-8"));

            Serializer serializer = new Persister();
            objClass = serializer.read(objClass, stream);
            return objClass;
    }
    catch (Exception e) 
    {
        return e;
    }
}

xmlFile 是(错误命名的)xml 字符串,objClass 是我要反序列化到的类的空类。这通常是其他对象的列表。

示例类:

@Root(name="DepartmentList")
public class DepartmentList {
    @ElementList(entry="Department", inline=true)
    public List<Department> DepartmentList =new ArrayList<Department>();
    public boolean FinishedPopulating = false;
}

部门类:

public class Department {

    @Element(name="DeptID")
    private String _DeptID ="";
    public String DeptID()
    {
        return _DeptID;
    }
    public void DeptID(String Value)
    {
        _DeptID = Value;
    }

    @Element(name="DeptDescription")
    private String _DeptDescription ="";
    public String DeptDescription()
    {
        return _DeptDescription;
    }
    public void DeptDescription(String Value)
    {
        _DeptDescription = Value;
    }
}

示例 XML:

<DepartmentList>
  <Department>
    <DeptID>525</DeptID>
    <DeptDescription>Dept 1</DeptDescription>
  </Department>
  <Department>
    <DeptID>382</DeptID>
    <DeptDescription>Dept 2</DeptDescription>
  </Department>
</DepartmentList>

这在整个应用程序中运行良好,但我已经到了需要反序列化列表中 >300 个对象的地步。这只需要大约 5 秒,或者在调试时接近一分钟,但用户对这种性能并不满意,并且在不需要调试时浪费了时间。有什么办法可以加快这个速度吗?还是我应该这样做的另一种方式?最好只通过更改deserializeXMLToObject 方法。

【问题讨论】:

  • 就这么简单——一种类型有一个列表和两个字段,还是现实中复杂得多?
  • 这是一种类型,但大约 300-400 行中可能有大约 30 个字段。我只是出于示例目的对其进行了简化。
  • 一种可能的解决方案是报告结果,而无需等待解析器解析整个内容
  • XML 很慢。考虑使用其他格式。
  • 谁能帮我这个链接:stackoverflow.com/questions/22385034/…

标签: java android performance deserialization simple-framework


【解决方案1】:

很久以前就有一个 SOAP Web 服务的类似问题。 最后我改变了 XML 的格式,转换了属性中的节点。

示例:

<node>
  <attr1>value1</attr1>
  <attr2>value2</attr2>
  <attr3>value3</attr3>
  <attr4>value4</attr4>
</node>

被转化为

<node attr1='value1'attr2='value2' attr3='value3' attr4='value4' />

从理论上讲,这可能不是最好的解决方案,但性能提升确实很好。 Ofc 如果您的 XML 有点复杂(不同级别的可重复节点或多级列表),事情可能会有点复杂。

【讨论】:

    【解决方案2】:

    就我的研究而言,这是优化的最佳方式:

    “Simple 将动态构建您的对象图,这意味着它将需要加载尚未加载的类,并使用反射基于其注释为每个类构建一个模式。所以第一次使用将永远是迄今为止最昂贵的。重复使用同一个持久化实例会快很多倍。所以尽量避免使用多个持久化实例,尽可能只使用一个。"

    因此,重构您的代码以使用相同的 Persister 应该会提高您的性能。

    我从question 得到的这个和其他提示。在那种情况下,这种重构提高了性能,正如作者所说(从 15s 到 3-5s)。

    希望对你有帮助

    【讨论】:

    • 使用相同的持久化器确实提高了性能,但只是轻微的。从 6.25 秒到 5.75 秒。 0.5s 的差异对仍然会抱怨的用户影响不大。
    【解决方案3】:

    使用服务器代理并将您的 XML 转换为 JSON

    【讨论】:

      【解决方案4】:

      我相信有人会指出一个更好的库,但根据one detailed answer,它们在 Android 上都很慢。

      所以这是我的快速破解(是的,我知道它不是很容易维护,并且对于没有完全按照指定的 XML 形成很脆弱)和一些结果:

      private void doTest()
      {
          Thread t = new Thread()
          {
              public void run()
              {
                  runOne(2000);
                  runOne(300);
                  runOne(20000);
              }
      
              private void runOne(int num)
              {
                  String start = "<DepartmentList>";
                  String mid1 =  "<Department>\n" +
                                  "<DeptID>";
                  String mid2 = "</DeptID>\n" +
                                  "<DeptDescription>Dept ";
                  String mid3 = "</DeptDescription></Department>";
                  String fin = "</DepartmentList>";
      
                  StringBuffer sb = new StringBuffer();
                  sb.append(start);
                  for (int i=0; i< num; i++)
                  {
                      sb.append(mid1);
                      sb.append(""+i);
                      sb.append(mid2);
                      sb.append(""+i);
                      sb.append(mid3);
                  }
                  sb.append(fin);
      
                  Pattern p = Pattern.compile(
                  "<Department\\s*>\\s*<DeptID\\s*>([^<]*)</DeptID>\\s*<DeptDescription\\s*>([^<]*)</DeptDescription>\\s*</Department>");
      
                  long startN = System.currentTimeMillis();
      
                  DepartmentList d = new DepartmentList();
                  List<Department> departments = d.DepartmentList;
      
                  Matcher m = p.matcher(sb);
                  while (m.find())
                  {
                      Department department = new Department();
                      department.DeptID(m.group(1));
                      department.DeptDescription(m.group(2));
                      departments.add(department);
                  }
      
                  long endN = System.currentTimeMillis();
      
                  Log.d("Departments", "parsed: " + departments.size() + " in " + (endN-startN) + " millis");
                  Log.d("Departments", "lastone: " + departments.get(departments.size() -1)._DeptID + " desc: " + departments.get(departments.size() -1)._DeptDescription);
      
              }
          };
          t.start();
      }
      
      public class DepartmentList {
          public List<Department> DepartmentList =new ArrayList<Department>();
          public boolean FinishedPopulating = false;
      }
      
      public class Department {
      
          private String _DeptID ="";
          public String DeptID()
          {
              return _DeptID;
          }
          public void DeptID(String Value)
          {
              _DeptID = Value;
          }
      
          private String _DeptDescription ="";
          public String DeptDescription()
          {
              return _DeptDescription;
          }
          public void DeptDescription(String Value)
          {
              _DeptDescription = Value;
          }
      }
      

      我将它粘贴到一个 Android 项目中,并从 onCreate() 方法中调用它。结果如下:

      Platform        num=300    num=2000     num=20000 
      =================================================
      Nexus 7         5          38           355
      Galaxy Y        29         430          1173
      HTC Desire HD   19         189          539
      Galaxy Nexus    14         75           379
      

      所有时间都以毫秒为单位。

      【讨论】:

      • 终于开始尝试这种方法。虽然我同意这不是最有效的方法,但我只有 1 个需要以这种方式反序列化的数据表,它提供了最快的解决方案。从 6.25 秒降至
      【解决方案5】:

      您可以通过直接序列化为 XML 并直接从 XML 反序列化来消除中间(反)序列化步骤,例如使用JAXBXStream

      您还可以通过多线程加快处理速度。我假设您要反序列化的所有 XML 字符串都在 ConcurrentLinkedQueue 中;或者,您可以同步访问您正在使用的任何非线程安全集合。使用 ThreadPoolExecutor 之类的东西来最小化线程创建开销。

      public class DeserializeXML implements Runnable {
          private final String xml;
          private final ConcurrentLinkedQueue<Object> deserializedObjects;
      
          public DeserializeXML(String xml, ConcurrentLinkedQueue deserializedObjects) {
              this.xml = xml;
              this.deserializedObjects = deserializedObjects;
          }
      
          public void run() {
              deserializedObjects.offer(deserializeXMLToObject(xml, Object.class));
          }
      }
      
      // ***
      
      ConcurrentLinkedQueue<String> serializedObjects;
      ConcurrentLinkedQueue<Object> deserializedObjects;
      ThreadPoolExecutor executor = new ThreadPoolExecutor;
      while(!serializedObjects.isEmpty()) {
          executor.execute(new DeserializeXML(serializedObjects.poll(), deserializedObjects));
      }
      

      【讨论】:

      • 反序列化是临时发生的。当一个事件发生时,它会关闭并反序列化一个字符串,当另一个事件发生时,它会反序列化另一个。它们没有存储在ConcurrentLinkedQueue 中,我什至不知道从哪里开始研究它。我查看了 JAXB 和 XStream 都没有工作。一个导致重复包名称的问题,另一个只是“不起作用”我不记得它的确切问题是什么。我将再次查看它们,但我希望能提供指向 JAXB 或 XStream 的教程或工作示例的链接,因为文档似乎很少。
      • 好的,经过更多研究,这些软件包似乎都不适用于 Android。我要筹集赏金。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-24
      • 1970-01-01
      • 2011-02-27
      相关资源
      最近更新 更多