Android Jsoup Parser在kitkat上非常慢
作者:互联网
Jsoup似乎在kitkat上解析的速度比在kitkat之前的解析要慢得多.我不确定它是否是ART运行时,但是在对一种解析方法进行速度测试后发现它慢了大约5倍,我也不知道为什么.
我的代码的这一部分在异步任务的doInBackground中运行.
JsoupParser parser = new JsoupParser();
parser.setPath(String.valueOf(application.getCacheDir()));
Collection<Section> allSections = eguide.getSectionMap().values();
for (Section section : allSections) {
parser.createNewAssetList();
parser.setContent(section.color, section.name, section.text, section.slug);
if (!TextUtils.isEmpty(section.text)) {
section.text = parser.setWebViewStringContent();
section.assets = parser.getAssets();
for (Asset asset : section.assets)
asset.heading = section.heading;
}
}
我是在很久以前写的,它可能不是很有效,但是它设置了解析器,加载了Section对象的列表,对于每个对象,它将html提取表和图像解析为不同对象的列表,这些对象返回到原始section对象..
这是我的解析器类.
public class JsoupParser{
private List<Asset> assets;
private int assetCount;
private String slug,name,color,path;
private Document doc;
public JsoupParser() {
assetCount = 0;
assets = new ArrayList<Asset>();
}
public void setPath(String path) {
this.path = path;
}
public void setContent(String color, String name, String text, String slug){
this.color = color;
this.name = name;
this.slug = slug;
doc = Jsoup.parse(text);
}
public void createNewAssetList(){
assetCount = 0;
assets = new ArrayList<Asset>();
}
public String setWebViewStringContent() {
addScriptsAndDivTags();
//parse images
Elements images = doc.select("img[src]");
parseImages(images);
//parse tables
Elements tableTags = doc.select("table");
parseTables(tableTags);
return doc.toString();
}
private void addScriptsAndDivTags() {
Element bodyReference = doc.select("body").first(); //grab head and body ref's
Element headReference = doc.select("head").first();
Element new_body = doc.createElement("body");
//wrap content in extra div and add accodrion tag
bodyReference.tagName("div");
bodyReference.attr("id", "accordion");
new_body.appendChild(bodyReference);
headReference.after(new_body);
}
private void parseTables(Elements tableTags) {
if (tableTags != null) {
int count = 1;
for (Element table : tableTags) {
Asset item = new Asset();
item.setContent(table.toString());
item.setColor(color);
item.id = (int) Math.ceil(Math.random() * 10000);
item.isAsset=1;
item.keywords = table.attr("keywords");
String linkHref = table.attr("table_name");
item.slug = "t_" + slug + " " + count ;
if(!TextUtils.isEmpty(linkHref)){
item.name = linkHref;
}
else{
item.name ="Table-" + (assetCount + 1) + " in " + name;
}
// replace tables
String inline = table.attr("inline");
String button = ("<p>Dummy Button</p>");
if(!TextUtils.isEmpty(inline)&& inline.contentEquals("false") || TextUtils.isEmpty(inline) )
{
table.replaceWith(new DataNode(button, ""));
}
else{
Element div = doc.createElement("div");
div.attr("class","inlineTableWrapper");
div.attr("onclick", "window.location ='table://"+item.slug+"';");
table.replaceWith(div);
div.appendChild(table);
}
assets.add(item);
assetCount++;
count++;
}
}
}
private void parseImages(Elements images) {
for (Element image : images) {
Asset item = new Asset();
String slug = image.attr("src");
//remove first forward slash from slug to account for img:// protocol in image linking
if(slug.charAt(0)=='/')
slug = slug.substring(1,slug.length());
image.attr("src", path +"/images/" + slug.substring(slug.lastIndexOf("/")+1, slug.length()));
image.attr("style", "px; border:1px solid #000000;");
String image_name = image.attr("image_name");
if(!TextUtils.isEmpty(image_name)){
item.name = image_name;
}
else{
item.name ="Image " + (assetCount + 1) + " in " + name;
}
// replace tables
String inline = image.attr("inline");
String button = ("<p>Dummy Button</p>");
item.setContent(image.toString()+"<br/><br/><br/><br/>");
if(!TextUtils.isEmpty(inline)&& inline.contentEquals("false"))
{
image.replaceWith(new DataNode(button, ""));
}
else{
image.attr("onclick", "window.location ='img://"+slug+"';");
}
item.keywords = image.attr("keywords");
item.setColor(color);
item.id = (int) Math.ceil(Math.random() * 10000);
item.slug = slug;
item.isAsset =2;
assets.add(item);
assetCount++;
}
}
public String getName() {
return name;
}
public List<Asset> getAssets() {
return assets;
}
}
同样,它的效率可能不是很高,但是到目前为止,我一直无法找出为什么它会对kitkat产生如此大的影响.任何信息将不胜感激.
谢谢!
解决方法:
更新2015年4月7日jsoup的作者将我的建议纳入了主干,此时检查ASCII或UTF编码并跳过慢速(在Android 4.4和5上)canEncode()调用,因此只需更新jsoup源代码树并重新构建,或者拉动他的最新罐子.
对此问题的早期评论和解释:我发现了问题所在,至少在我的应用程序中-jsoup的Entities.java模块具有escape()函数-例如通过Element.outerHtml()调用所有文本节点.其中,它会测试每个文本节点的每个字符是否可以使用当前编码器进行编码:
if (encoder.canEncode(c))
accum.append(c);
else...
在Android KitKat和Lollipop上,canEncode()调用速度极慢.由于我的HTML输出仅是UTF-8,而Unicode实际上可以编码任何字符,因此此检查不是必需的.我通过在escape()函数开始时进行测试来更改它:
boolean encIsUnicode = encoder.charset().name().toUpperCase().startsWith("UTF-");
然后在需要测试时:
if (encIsUnicode || encoder.canEncode(c))
accum.append(c);
else ...
现在,我的应用程序在KitKat和Lollipop上也像超级魅力一样工作-以前耗时10秒,现在不到1秒.通过此更改和一些较小的优化,我向主jsoup存储库发出了pull请求.不知道jsoup作者是否会合并它.如果需要,请在以下位置查看我的叉子:
https://github.com/gregko/jsoup
如果您使用预先知道的其他编码,则可以添加自己的测试(例如,查看字符是否为ASCII或其他字符),以避免调用canEncode(c)造成的费用.
格雷格
标签:performance,android-4-4-kitkat,jsoup,parsing,android 来源: https://codeday.me/bug/20191121/2048825.html