Android TextView 프 리 렌 더 링 연구

Android 의 TextView 는 전체 프레임 워 크 에서 가장 복잡 한 컨트롤 중 하나 로 Android 에서 텍스트 를 표시 하 는 대부분의 작업 을 담당 합 니 다.framwork 의 많은 컨트롤 도 TextView,예 를 들 어 Button,EditText 등 을 직접 또는 간접 적 으로 계승 합 니 다.그 내부 실현 도 상당히 복잡 하 다.단 론 코드 줄 수 를 보면 안 드 로 이 드-22 에서 TextView 는 무려 9509 줄 이 있다.또한 TextView 에서 많은 조작 이 매우 무겁다.예 를 들 어 setText 작업 은 SpanWatcher 를 설정 하거나 SpannableString 을 재현 해 야 한다.상황 에 따라 Text Layout 를 다시 만들어 야 한다.이 조작 들 을 합치 면 setText 작업 에 시간 이 많이 걸 립 니 다.TextView 의 렌 더 링 효율 을 높이 기 위해 최근 에 미리 렌 더 링 하 는 방법 을 연구 한 다음 에 원 리 를 설명해 드 리 겠 습 니 다.
TextView 렌 더 링 기본 원리
먼저 TextView 의 기본 렌 더 링 원 리 를 소개 합 니 다.전체적으로 보면 TextView 에서 렌 더 링 문 자 를 담당 하 는 것 은 주로 이 세 가지 유형 입 니 다.
BoringLayout
주로 한 줄 의 텍스트 를 표시 하고 isBoring 방법 을 제공 하여 한 줄 의 텍스트 조건 을 만족 시 키 는 지 판단 합 니 다.
DynamicLayout
텍스트 가 Spannable 일 때 TextView 는 텍스트 디 스 플레이 를 담당 하기 위해 이 를 사용 하고,내부 에 SpanWatcher 를 설정 하 며,span 변경 사항 이 감지 되면 reflow 를 해서 레이아웃 을 다시 계산 합 니 다.
StaticLayout
텍스트 가 한 줄 이 아 닌 텍스트 이 고 Spannable 이 아 닐 때 StaticLayout 를 사용 합 니 다.내부 에 span 의 변 화 를 감청 하지 않 기 때문에 효율 적 으로 DynamicLayout 보다 높 습 니 다.레이아웃 을 한 번 만 만 들 면 됩 니 다.그러나 내부 에 도 SpannableString 이 표 시 됩 니 다.span 이 변 한 후에 레이아웃 을 다시 할 수 없 을 뿐 입 니 다.
또한 상기 세 가지 유형 은 모두 Layout 류 에 계승 되 어 있 습 니 다.이러한 과정 에서 텍스트 의 구체 적 인 그립 니 다.Layout.draw 방법 에서 텍스트 한 줄 한 줄 을 렌 더 링 합 니 다.

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);

Spannble 이나 emoji 가 포 함 된 텍스트 를 알 수 있다 면 실제 렌 더 링 작업 은 TextLine 에 맡 겨 그립 니 다.그렇지 않 으 면 canvas.drawText 를 직접 사용 합 니 다.TextLine 은 한 줄 의 복잡 한 텍스트 를 그립 니 다.그 중에서 Spannable,Emoji 와 같은 그리 기 논 리 는 모두 포함 되 어 있 고 TextLine 의 그리 기 논리 도 효율 적 이지 않 습 니 다.여기 서 후속 적 으로 그것 이 어떻게 최적화 되 어야 하 는 지 계속 설명 할 것 이다.
TextLayoutCache
Canvas 는 drawText 를 사용 할 때 글꼴 의 크기,여백 등 을 매번 계산 해 야 할 경우 시간 이 많이 걸 려 drawText 시간 이 길 어 집 니 다.효율 성 을 높이 기 위해 안 드 로 이 드 는 4.0 이후 TextLayoutCache 를 도 입 했 고 LRU Cache 를 사용 하여 글꼴,여백 등 데 이 터 를 캐 시 하여 drawText 의 속 도 를 높 였 습 니 다.4.4 에서 이 cache 의 크기 는 0.5M 입 니 다.전역 적 으로 사용 되 며,Activity 의 configurationChanged,onResume,lowMemory,updateVisibility 등 시기 에 Canvas.freeTextLayoutCache 를 호출 하여 이 메모 리 를 방출 합 니 다.이 부분의 cache 는 시스템 의 하부 통제 이기 때문에 우 리 는 구체 적 인 통 제 를 할 수 없다.
TextView 의 프 리 렌 더 링 최적화
TextView 의 렌 더 링 원 리 를 보면 단순히 텍스트 를 표시 하 는 것 이 라면 SpanWatcher 를 따로 설정 하여 span 의 변 화 를 감청 할 필요 가 없습니다.따라서 저 희 는 BoringLayout 나 StaticLayout 를 직접 사용 하여 텍스트 내용 을 직접 표시 할 수 있 습 니 다.그러나 BoringLayout 는 한 줄 의 텍스트 만 표시 할 수 있 기 때문에 여기 서 가장 좋 은 선택 은 StaticLayout 을 직접 사용 하 는 것 입 니 다.
사용자 정의 View 를 선 택 했 습 니 다.마지막 으로 이러한 인터페이스 가 있 기 를 바 랍 니 다.

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();
  }
}

이 view 의 Layout 를 설정 하여 텍스트 를 직접 그 릴 수 있 으 며,onDraw 방법 에서 이 Layout 대상 을 직접 사용 하여 텍스트 를 그 릴 수 있 습 니 다.여기 서 우 리 는 setText 방법 을 버 리 고 Layout 를 통 해 텍스트 를 직접 그립 니 다.여기 있 는 Layout 대상 은 미리 만 든 후에 설정 할 수 있 습 니 다.(여 기 는 하나의 스 레 드 에 넣 어서 만 들 수 있 습 니 다)일반 TextView 의 setText 방법 보다 setText 의 많은 소 모 를 줄 이 고 효율 을 크게 향상 시 킬 수 있 습 니 다.
Static Layout 의 생 성 은 매우 간단 합 니 다.주어진 텍스트,너비 등 만 있 으 면 바로 만 들 수 있 습 니 다.또한,TextLayoutCache 를 미리 채 우기 위해 서 는 StaticLayout 대상 을 만 든 후에 미리 Dummy canvas 에서 draw 할 수 있 습 니 다.
StaticLayout layout = new StaticLayout(TestSpan.getSpanString(i), textPaint, hardCodeWidth, alignment, 1.0f, 0f, true);
layout.draw(dummyCanvas);
성능 대비
다음은 구체 적 인 성능 을 테스트 해 보 겠 습 니 다.여기 testcase 는 Github 에 올 렸 습 니 다StaticLayoutView
testcase 의 내용 은 하나의 ListView 에 300 개의 Item 을 표시 합 니 다.각 item 은 순수한 텍스트 입 니 다.그 안에 대량의 ImageSpan 이 포 함 된 SpannableString 이 포함 되 어 있 습 니 다.양쪽 을 비교 하면 StaticLayout 를 직접 사용 하고 일반 TextView 를 사용 합 니 다.또한 이 300 개의 텍스트 는 모두 같 지 않 고 길이 가 다 르 며 무 작위 로 생 성 됩 니 다.StaticLayout 의 testcase 에서...Static Layout 는 다른 스 레 드 가 만들어 진 후에 미리 설정 되 어 있 으 며,또한 SpannableString 도 미리 생 성 되 어 있 습 니 다.
또한 실제 app 의 힘 든 배경 작업 을 모 의 하기 위해 3 개의 스 레 드 를 만 들 었 고 CPU 자원 을 선점 하기 위해 부동 소수점 예산 을 계속 만 들 었 습 니 다.
성능 을 측정 하 는 지 표 는 ListView 가 연속 적 으로 아래로 굴 러 가 고 평균 프레임 율 이 얼마 인지 측정 하 며 각각 다섯 번 측정 하여 평균 치 를 계산 하 며 최종 성능 테스트 결 과 는 다음 과 같다.

여기 서 테스트 하 는 기 계 는 MX3 이 고 왼쪽 은 Static Layout 를 직접 사용 하 는 방안 이 며 오른쪽 은 시스템 의 기본 방안 이 며 Y 축 은 FPS 로 최적화 된 방안 을 사용 하여 프레임 율 이 많이 향상 되 었 음 을 알 수 있다.
References
Improving Comment Rendering on Android
이 글 은 인 스타 그램 이 TextView 렌 더 링 의 효율 을 어떻게 최적화 하 는 지 를 소개 했다.이것 도 이곳 의 최적화 방법의 원천 이다.인 스타 그램 도 Static Layout 를 직접 사용 하고 Layout 를 미리 만 드 는 방법 으로 ListView 스크롤 과정 에서 프레임 이 떨 어 지 는 확률 을 줄 이 고 효과 가 매우 현저 하 다.이 글 은 이곳 의 원리 해석 과 간단 한 실현 을 제시 한 셈 이다.
이상 은 Android TextView 에 미리 보 여 준 자 료 를 정리 하고 관련 자 료 를 계속 보충 하 는 것 입 니 다.본 사이트 에 대한 지원 에 감 사 드 립 니 다!

좋은 웹페이지 즐겨찾기