最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android TextView預(yù)渲染研究

 更新時(shí)間:2016年09月20日 09:04:44   作者:MrlLee  
這篇文章主要介紹了Android TextView預(yù)渲染研究的相關(guān)資料,需要的朋友可以參考下

Android中的TextView是整個(gè)framework中最復(fù)雜的控件之一,負(fù)責(zé)Android中顯示文本的大部分工作,framwork中的許多控件也直接或者間接的繼承于TextView,例如Button,EditText等。其內(nèi)部實(shí)現(xiàn)也相當(dāng)復(fù)雜,單論代碼行數(shù)來說,android-22中TextView有足足9509行,另外,TextView中許多操作都非常繁重,例如setText操作,需要設(shè)置SpanWatcher,或者需要重現(xiàn)創(chuàng)建一個(gè)SpannableString,還需要根據(jù)情況重新創(chuàng)建Text Layout,這些操作加起來之后令一次setText操作非常耗時(shí)。為了提升TextView的渲染效率,最近研究了一下預(yù)渲染的方法,接下來給大家講解一下原理。

TextView渲染基本原理

首先來介紹下TextView的基本渲染原理,總的來說,TextView中負(fù)責(zé)渲染文字的主要是這三個(gè)類:

BoringLayout

主要負(fù)責(zé)顯示單行文本,并提供了isBoring方法來判斷是否滿足單行文本的條件。

DynamicLayout

當(dāng)文本為Spannable的時(shí)候,TextView就會(huì)使用它來負(fù)責(zé)文本的顯示,在內(nèi)部設(shè)置了SpanWatcher,當(dāng)檢測(cè)到span改變的時(shí)候,會(huì)進(jìn)行reflow,重新計(jì)算布局。

StaticLayout

當(dāng)文本為非單行文本,且非Spannable的時(shí)候,就會(huì)使用StaticLayout,內(nèi)部并不會(huì)監(jiān)聽span的變化,因此效率上會(huì)比DynamicLayout高,只需一次布局的創(chuàng)建即可,但其實(shí)內(nèi)部也能顯示SpannableString,只是不能在span變化之后重新進(jìn)行布局而已。

另外,以上三個(gè)類都繼承于Layout類,在此類中統(tǒng)一負(fù)責(zé)文本的具體繪制,在Layout.draw方法中,會(huì)對(duì)文本一行一行的進(jìn)行渲染:

TextLine tl = TextLine.obtain();
 
// Draw the lines, one at a time.
// The baseline is the top of the following line minus the current line's descent.
for (int i = firstLine; i <= lastLine; i++) {
   ....
   Directions directions = getLineDirections(i);
   if (directions == DIRS_ALL_LEFT_TO_RIGHT && !mSpannedText && !hasTabOrEmoji) {
     // XXX: assumes there's nothing additional to be done
     canvas.drawText(buf, start, end, x, lbaseline, paint);
   } else {
     tl.set(paint, buf, start, end, dir, directions, hasTabOrEmoji, tabStops);
     tl.draw(canvas, x, ltop, lbaseline, lbottom);
   }
}
TextLine.recycle(tl);

可以看出來對(duì)于Spannble,或者包含emoji的文本的話,實(shí)際渲染操作是交給了TextLine去繪制,否則直接使用canvas.drawText,TextLine負(fù)責(zé)單行復(fù)雜文本的繪制,其中Spannable, Emoji之類的繪制邏輯都包含在里面,TextLine的繪制邏輯也并非十分高效,這里后續(xù)將會(huì)繼續(xù)說明其應(yīng)該如何優(yōu)化。

TextLayoutCache

Canvas在drawText的時(shí)候,如果需要每次都計(jì)算字體的大小,邊距等之類的話,就會(huì)非常耗時(shí),導(dǎo)致drawText時(shí)間會(huì)拉的很長(zhǎng),為了提高效率,android在4.0之后引入了TextLayoutCache,使用LRU Cache緩存了字形,邊距等數(shù)據(jù),提升了drawText的速度,在4.4中,這個(gè)cache的大小是0.5M,全局使用,并且會(huì)在Activity的configurationChanged, onResume, lowMemory, updateVisibility等時(shí)機(jī),會(huì)調(diào)用Canvas.freeTextLayoutCache來釋放這部分內(nèi)存。由于這部分的cache是系統(tǒng)底層控制的,我們無法做具體的控制。

TextView的預(yù)渲染優(yōu)化

從TextView的渲染原理來看,如果只是單純的顯示文本,我們根本不需要另外設(shè)置SpanWatcher來監(jiān)聽span的變化,因此我們可以直接使用BoringLayout或者StaticLayout來直接顯示文本內(nèi)容,但是BoringLayout只能顯示單行文本,因此這里最好的選擇是直接用StaticLayout

我們選擇了自定義View,并希望最終有這樣的一個(gè)接口:

public class StaticLayoutView extends View {
  private Layout layout = null;
  public void setLayout(Layout layout) {
    this.layout = layout;
    requestLayout();
  } 
  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
 
    canvas.save();
    if (layout != null) {
      layout.draw(canvas, null, null, 0);
    }
    canvas.restore();
  }
}

我們可以直接通過設(shè)置這個(gè)view的Layout來繪制文本,并在onDraw方法中直接使用這個(gè)Layout對(duì)象來繪制文本。在這里我們摒棄了setText方法,直接通過Layout來繪制文本,而這里的Layout對(duì)象,我們可以通過預(yù)先創(chuàng)建之后才設(shè)置進(jìn)去(這里可以放到單獨(dú)的一個(gè)線程中創(chuàng)建),這樣對(duì)比起普通TextView的setText方法,我們減少了setText中的許多消耗,可以大幅度的提升效率。

StaticLayout的創(chuàng)建非常簡(jiǎn)單,只需要給定文本,寬度等就能直接創(chuàng)建。另外,為了預(yù)先填充TextLayoutCache,我們也可以在創(chuàng)建完StaticLayout對(duì)象之后,預(yù)先在一個(gè)dummy canvas中draw出來:

StaticLayout layout = new StaticLayout(TestSpan.getSpanString(i), textPaint, hardCodeWidth, alignment, 1.0f, 0f, true);
layout.draw(dummyCanvas);

性能對(duì)比

接下來我們測(cè)試一下具體的性能,這里的testcase放到了Github上:StaticLayoutView

testcase的內(nèi)容為,在一個(gè)ListView中,顯示300個(gè)Item,每個(gè)item都是一段純文本,里面全都是包含有大量ImageSpan的SpannableString,進(jìn)行兩邊的對(duì)比,一邊是直接使用StaticLayout,一邊是使用普通的TextView,并且這300段文本不全相同,長(zhǎng)度不同,隨機(jī)生成,在StaticLayout的testcase中,StaticLayout都是預(yù)先在另外一個(gè)線程創(chuàng)建好之后才設(shè)置進(jìn)去的,另外SpannableString也是預(yù)先生成好的。

另外,在這里為了模擬真實(shí)app繁重的后臺(tái)工作,另外創(chuàng)建了3個(gè)線程,不停在做浮點(diǎn)預(yù)算以嘗試搶占CPU資源。

測(cè)量性能的指標(biāo)為,ListView連續(xù)向下滾動(dòng),測(cè)量其平均幀率為多少,分別測(cè)量五次,計(jì)算其平均值,最終性能測(cè)試結(jié)果如下:

這里測(cè)試的機(jī)器是MX3,左側(cè)是直接使用StaticLayout的方案,右側(cè)是系統(tǒng)的默認(rèn)方案,Y軸是FPS,可以看出來,使用優(yōu)化之后的方案,幀率提升了許多。

References

Improving Comment Rendering on Android

這篇文章介紹了Instagram如何優(yōu)化他們的TextView渲染的效率,這也是這里優(yōu)化方法的來源,Instagram也是直接使用StaticLayout并通過預(yù)先創(chuàng)建Layout的方法來減少了ListView滾動(dòng)過程中的掉幀率,并且效果非常顯著。這篇文章算是給出了這里的原理解析以及一個(gè)簡(jiǎn)單的實(shí)現(xiàn)

以上就是對(duì)Android TextView預(yù)渲染 的資料整理,后續(xù)繼續(xù)補(bǔ)充相關(guān)資料,謝謝大家對(duì)本站的支持!

相關(guān)文章

最新評(píng)論

临潭县| 大宁县| 齐齐哈尔市| 界首市| 阳山县| 海宁市| 景德镇市| 板桥市| 确山县| 甘德县| 睢宁县| 岳西县| 抚远县| 灵丘县| 西乌| 大安市| 临夏县| 阜阳市| 江城| 社会| 南澳县| 黄浦区| 岑巩县| 寿宁县| 台南县| 基隆市| 社会| 烟台市| 格尔木市| 江永县| 吉隆县| 新乡县| 家居| 宜丰县| 东至县| 宾阳县| 濮阳市| 饶平县| 临沂市| 尼勒克县| 吉安县|