2014-10-22 88 views
0

我想做一个列表视图有TextView元素,其中每个包含一个SpannableString。这些TextView的内容从Html标记中的ArrayList中获取,并使用Html.fromHtml转换为SpannableStrings。现在,Html.fromHtml有很多性能问题。于是,我就使Html.fromHtmlHtml.fromHtml的替代软件?

class NeoHTML extends DefaultHandler { 

SpannableStringBuilder s; 
String html; 
Context context; 

public NeoHTML(String html,Context context) { 
    s = new SpannableStringBuilder(""); 
    this.html = html; 
    this.context=context; 
    getXml(); 
} 

public SpannableStringBuilder fromHTML() { 
    return s; 
} 


public void getXml() { 
    try { 

     SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); 
     SAXParser saxParser = saxParserFactory.newSAXParser(); 
     DefaultHandler defaultHandler = new DefaultHandler() { 

      int boldTag = 0; 
      int italicsTag = 0; 
      int underlineTag = 0; 
      int pointer = 0; 
      boolean brpassed=false; 
      public void startElement(String uri, String localName, 
        String qName, Attributes attributes) 
        throws SAXException { 

       if (qName.equalsIgnoreCase("B")) { 
        boldTag += 1; 
       } 
       if (qName.equalsIgnoreCase("I")) { 
        italicsTag += 1; 
       } 
       if (qName.equalsIgnoreCase("U")) { 
        underlineTag += 1; 
       } 
      } 

      public void characters(char ch[], int start, int length) 
        throws SAXException { 
       int tstart=start; 


        if(new String(ch, start, length).startsWith("[ ]")){ 
         s.append("b"); 
         Typeface font = Typeface.createFromAsset(context.getAssets(), "tickfont.ttf"); 
         s.setSpan (new CustomTypefaceSpan("", font),pointer, pointer+1,Spanned.SPAN_EXCLUSIVE_INCLUSIVE); 
         pointer+=1; 
         tstart+=3; 
        } 

        else if(new String(ch, start, length).startsWith("[*]")){ 
         s.append("a"); 
         Typeface font = Typeface.createFromAsset(context.getAssets(), "tickfont.ttf"); 
         s.setSpan (new CustomTypefaceSpan("", font),pointer, pointer+1,Spanned.SPAN_EXCLUSIVE_INCLUSIVE); 
         pointer+=1; 
         tstart+=3; 
        } 



       if (boldTag > 0 || italicsTag > 0 || underlineTag > 0) { 
        s.append(new String(ch, tstart, length)); 
        if (boldTag > 0) { 

         s.setSpan(new StyleSpan(
           android.graphics.Typeface.BOLD), pointer, 
           pointer + length, 
           Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 

        } 
        if (italicsTag > 0) { 

         s.setSpan(new StyleSpan(
           android.graphics.Typeface.ITALIC), pointer, 
           pointer + length, 
           Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 

        } 
        if (underlineTag > 0) { 

         s.setSpan(new UnderlineSpan(), pointer, pointer 
           + length, 
           Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 
        } 

       } else { 
        s.append(new String(ch, tstart, length)); 
       } 

       pointer += length; 
      } 

      public void endElement(String uri, String localName, 
        String qName) throws SAXException { 

       if (qName.equalsIgnoreCase("B")) { 
        boldTag -= 1; 
       } 
       if (qName.equalsIgnoreCase("BR")) { 
        s.append("\n"); 
        pointer+=1; 
        brpassed=true; 
       } 
       if (qName.equalsIgnoreCase("I")) { 
        italicsTag -= 1; 
       } 
       if (qName.equalsIgnoreCase("U")) { 
        underlineTag -= 1; 
       } 
      } 
     }; 
     saxParser.parse(new InputSource(new StringReader(html)), 
       defaultHandler); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

}我自己的版本

这是一个简单的基于SAX解析器。我的灵感来自CommonsWare Is there a faster way to decode html characters to a string than Html.fromHtml()?的回答。它具有最小的功能(粗体,斜体,下划线和中断)但即便如此,性能并没有得到改善。我有一些想法,比如将textview合成为位图并将其缓存在内存中,而不必在listview回收时再次将其重新渲染。任何人都可以提出任何想法..(请避免NDK为基础的解决方案,因为我从来没有成功编译任何它们,它增加了不必要的复杂性)

+0

试图使用“低级”拉解析器? – pskink 2014-10-22 08:31:34

+0

@pskink,我不希望它太复杂。这是一个小问题。添加NDK不是一种选择。抱歉。 但你能建议一个好的低级解析器吗? – avinayak 2014-10-22 08:38:51

+0

复杂?你的意思是简单吗?请参阅:http://pastebin.com/6yU3tGaR – pskink 2014-10-22 09:06:29

回答

2

我有一个类似的问题,而当我做了Html.fromHtml文本是模糊的某些设备上时必须大胆。所以这是我的解决方案:

public static Spannable boldFromHtml(Context c, String text, boolean extraBold){ 
    String textTemp = text; 

    int boldStartPos = 0; 
    int boldEndPos = 1; 
    List<int[]> spanList = new LinkedList<int[]>(); 

    while((boldStartPos = textTemp.indexOf("<b>", boldStartPos)) != -1 && (boldEndPos = textTemp.indexOf("</b>", boldStartPos) - 3) != -1){ 
     textTemp = textTemp.replaceFirst("<b>", "").replaceFirst("</b>", ""); 
     spanList.add(new int[]{boldStartPos, boldEndPos}); 
     boldStartPos += 3; 
    } 

    Spannable span = new SpannableString(textTemp); 
    for(int[] selection: spanList){ 
     span.setSpan(new BoldTypefaceSpan("sans-serif", (extraBold) ? MyExtraBoldFont(c) : MyBoldFont(c)), selection[0], selection[1], Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 
    } 

    return span; 
} 

此功能只粗体显示您的元素,但它可以很容易地修改为执行其他标记。

+0

这与我的尝试类似。我不认为这会提高性能 – avinayak 2014-10-22 08:39:58