当前位置:网站首页>PrecomputedTextCompat用法及原理
PrecomputedTextCompat用法及原理
2022-06-28 11:38:00 【一杯苦芥】
一、官方介绍
文本展示非常复杂,其涵盖的特性有:多种字体、行间距、字间距、文本方向、断行、字符连接等。为了测量及布局给定文本,TextView 必须做很多工作,例如读取字体文件、查找字形、决定形状、测量边界框以及将文本缓存在内部文本缓存中。更重要的是,所有这些工作都在 UI 线程中进行,这就有可能导致 app 帧数下降。
我们发现文本测量花费的时间占据文本设置的90%。为解决这一问题,在 Android P 中,以及作为 Jetpack 的一部分,我们推出了一个新的 API: PrecomputedText。该 API 早先在 API 14中便可以通过 PrecomputedTextCompat 访问。
PrecomputedTextCompat能够使 app 可以事先甚至在后台线程中执行文本布局最耗费时间的部分工作,以缓存布局结果,并返回宝贵的测量数据。然后,可以在 TextView 中设置结果。这样,只有大约10%的工作留给 TextView 执行。
二、使用方法
- compileSdkVersion不低于28,appcompat-v7 28.0.0或androidx appcompat 1.0.0及以上
- 使用AppCompatTextView来替换TextView
- 使用setTextFuture 替换 setText 方法
Java示例:
Future<PrecomputedTextCompat> future = PrecomputedTextCompat.getTextFuture(“text”,
textView.getTextMetricsParamsCompat(), null);
textView.setTextFuture(future);Kotlin示例:
fun AppCompatTextView.setTextFuture(charSequence: CharSequence){
this.setTextFuture(PrecomputedTextCompat.getTextFuture(
charSequence,
TextViewCompat.getTextMetricsParams(this),
null
))
}
textView.setTextFuture(“text”)三、实现原理
PrecomputedTextCompat将耗时的测量放到FutureTask异步执行:
@UiThread
public static Future<PrecomputedTextCompat> getTextFuture(
@NonNull final CharSequence charSequence, @NonNull PrecomputedTextCompat.Params params,
@Nullable Executor executor) {
PrecomputedTextFutureTask task = new PrecomputedTextFutureTask(params, charSequence);
if (executor == null) {
synchronized (sLock) {
if (sExecutor == null) {
sExecutor = Executors.newFixedThreadPool(1);
}
executor = sExecutor;
}
}
executor.execute(task);
return task;
}AppCompatTextView在onMeasure方法调用consumeTextFutureAndSetBlocking()时,future.get()阻塞线程获取测量的结果。最终setText到TextView上显示。
public void setTextFuture(@Nullable Future<PrecomputedTextCompat> future) {
mPrecomputedTextFuture = future;
if (future != null) {
requestLayout();
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
consumeTextFutureAndSetBlocking();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private void consumeTextFutureAndSetBlocking() {
if (mPrecomputedTextFuture != null) {
try {
Future<PrecomputedTextCompat> future = mPrecomputedTextFuture;
mPrecomputedTextFuture = null;
TextViewCompat.setPrecomputedText(this, future.get());
} catch (InterruptedException | ExecutionException e) {
// ignore
}
}
}- Android 9.0以上,使用PrecomputedText实现。
- Android 5.0~9.0,使用StaticLayout实现。
- Android 5.0以下,不做处理。
/**
* A helper class for computing text layout in background
*/
private static class PrecomputedTextFutureTask extends FutureTask<PrecomputedTextCompat> {
private static class PrecomputedTextCallback implements Callable<PrecomputedTextCompat> {
private PrecomputedTextCompat.Params mParams;
private CharSequence mText;
PrecomputedTextCallback(@NonNull final PrecomputedTextCompat.Params params,
@NonNull final CharSequence cs) {
mParams = params;
mText = cs;
}
@Override
public PrecomputedTextCompat call() throws Exception {
return PrecomputedTextCompat.create(mText, mParams);
}
}
PrecomputedTextFutureTask(@NonNull final PrecomputedTextCompat.Params params,
@NonNull final CharSequence text) {
super(new PrecomputedTextCallback(params, text));
}
}/**
* Create a new {@link PrecomputedText} which will pre-compute text measurement and glyph
* positioning information.
* <p>
* This can be expensive, so computing this on a background thread before your text will be
* presented can save work on the UI thread.
* </p>
*
* Note that any {@link android.text.NoCopySpan} attached to the text won't be passed to the
* created PrecomputedText.
*
* @param text the text to be measured
* @param params parameters that define how text will be precomputed
* @return A {@link PrecomputedText}
*/
public static PrecomputedTextCompat create(@NonNull CharSequence text, @NonNull Params params) {
Preconditions.checkNotNull(text);
Preconditions.checkNotNull(params);
try {
TraceCompat.beginSection("PrecomputedText");
// 省略此处代码
// No framework support for PrecomputedText
// Compute text layout and throw away StaticLayout for the purpose of warming up the
// internal text layout cache.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
StaticLayout.Builder.obtain(text, 0, text.length(), params.getTextPaint(),
Integer.MAX_VALUE)
.setBreakStrategy(params.getBreakStrategy())
.setHyphenationFrequency(params.getHyphenationFrequency())
.setTextDirection(params.getTextDirection())
.build();
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
new StaticLayout(text, params.getTextPaint(), Integer.MAX_VALUE,
Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
} else {
// There is no way of precomputing text layout on API 20 or before
// Do nothing
}
return new PrecomputedTextCompat(text, params, result);
} finally {
TraceCompat.endSection();
}
}// null on API 27 or before. Non-null on API 29 or later
private final @Nullable PrecomputedText mWrapped;
边栏推荐
- Day23 JS notes 2021.09.14
- fatal: unsafe repository (‘/home/anji/gopath/src/gateway‘ is owned by someone else)
- 【sciter】: sciter-fs模块扫描文件API的使用及其注意细节
- Zero basic C language (I)
- Day24 JS notes 2021.09.15
- JS foundation 8
- Unity屏幕截图功能
- Random forest and poetry maker trained by AMR
- AcWing 605. Simple product (implemented in C language)
- Array method in JS 2021.09.18
猜你喜欢

Practice and Thinking on the architecture of a set of 100000 TPS im integrated message system

Still using simpledateformat for time formatting? Be careful that the project collapses!

开源项目维权成功案例: spug 开源运维平台成功维权

New listing of operation light 3.0 - a sincere work of self subversion across the times!

2018 joint examination of nine provinces & Merging of line segment trees

Remote login sshd service

Is it feasible to be a programmer at the age of 26?

Using soapUI to obtain freemaker's FTL file template

day39 原型链及页面烟花效果 2021.10.13

day37 js笔记 运动函数 2021.10.11
随机推荐
Allez, Meta - Cosme, comme prévu, cette chaleur ne durera pas longtemps.
Int~long long indicates the maximum and minimum number
2. single digit statistics
【北京航空航天大学】考研初试复试资料分享
IO stream of file and Base64
零基础C语言(一)
SEO优化的许多好处是与流量有直接关系
Daily practice of C language - day 4: find the sum of all even numbers within 100
Come on, yuanuniverse. Sure enough, the heat won't pass for a while
Practice and Thinking on the architecture of a set of 100000 TPS im integrated message system
AcWing 607. Average 2 (implemented in C language)
赛尔号抽奖模拟求期望
js中this的默认指向及如何修改指向 2021.11.09
建立自己的网站(18)
Is it feasible to be a programmer at the age of 26?
Redis principle - List
【C语言】关于scanf()与scanf_s()的一些问题
AGCO AI frontier promotion (2.16)
AcWing 606. Average 1 (implemented in C language)
6.A-B