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提取表和图像到一个不同对象的列表,这些对象返回到原节对象..
这是我的解析器类。
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产生如此大的影响。任何信息都会非常值得赞赏。 谢谢!
答案 0 :(得分:3)
更新2015年4月7日 jsoup的作者将我的建议纳入主干,此时检查ASCII或UTF编码并跳过慢速(在Android 4.4和5上)canEncode( )调用,所以只需更新你的jsoup源代码树并重新构建,或者拉出他最新的jar。
此问题的早期评论和解释:我发现问题是什么,至少在我的应用中 - 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)调用。
格雷格
答案 1 :(得分:0)
你确实使用了很多字符串连接(这可能是大量数据的杀手)
item.name ="Table-" + (assetCount + 1) + " in " + name;
根据这篇文章:Is it always a bad idea to use + to concatenate strings - 你应该避免在循环中进行仲裁 - 你的代码就是这种情况..怎么样:
item.name = String.format(“%s中的表格%s”,assetCount + 1,名称);