问题描述:
客户反馈投诉说:
低端设备上,在桌面时,当音乐名过长时,音乐名称就会有一个跑马灯动态效果,此时调节设备的音量,设备极其的卡,音量调节界面会晚将近10秒才显示。
但是如果音乐名不长可以正常显示时,音乐名称就不会有跑马灯动态效果,此时调节设备的音量,设备正常,音量调节界面也不会慢显示。
歌名跑马灯动态显示效果:
初步处理
此问题先是反馈到应用组桌面负责的同志,这个因为原因比较简单,就是因为跑马灯动态显示效果显示导致,那直接将此效果关闭就解决了此问题了。
跑马灯动态显示效果的代码也是非常简单,就是设置TextView的几个属性:
<TextView
......
android:marqueeRepeatLimit="marquee_forever"
android:ellipsize="marquee"
android:focusable="true"
android:focusableInTouchMode="true"
android:scrollHorizontally="true"
大家以为就这样解决了,不是的,这仅仅只是一个开始,为什么了?
最核心的原因是,如果这样修改,需要给各个客户发不同的升级包来处理此问题,而事实上此桌面应用的客户有上百个客户,发每个客户发升级包不现实。所以领导决定此问题让系统组来统一处理此问题。
初步分析
1.分析桌面应用的traceview日志:
a.跑马灯动态显示时桌面应用的traceview日志,将方法调用次数按倒数来排序:
直接关闭跑马灯动态显示效果
b.无跑马灯动态显示时桌面应用的traceview日志,将方法调用次数按倒数来排序:
可以看出,跑马灯动态显示时桌面应用在特别频繁的刷新界面,其次数特别多。
2.查看界面刷新情况
将设置中开发者选项--显示面(surface)更新打开
可以看到在跑马灯动态显示歌词时,桌面应用在不断的闪红色,表示桌面应用在不断的刷新。当无跑马灯动态显示歌词时,桌面应用在几秒钟才闪一次红色,表示桌面应用在几秒才的刷新一次。
从上面二点,都可以看出这就是TextView的跑马灯动态显示歌词效果,引起的界面频繁刷新,从而导致系统卡。
追踪源码
明显这就是TextView跑马灯效果的一个系统设计导致的低端设备上的一个性能问题,那我们就去看一下这个实现情况吧。
需要重点关注二个属性:
android:marqueeRepeatLimit="marquee_forever"
android:ellipsize="marquee"
其对应在源码:
frameworks\base\core\java\android\widget\TextView.java
方法一:TextView--TextView方法中:
ellipsize和marqueeRepeatLimit属性赋值:
case com.android.internal.R.styleable.TextView_ellipsize:
ellipsize = a.getInt(attr, ellipsize);
break;
case com.android.internal.R.styleable.TextView_marqueeRepeatLimit:
setMarqueeRepeatLimit(a.getInt(attr, mMarqueeRepeatLimit));
break;
......
switch (ellipsize) {
case 1:
setEllipsize(TextUtils.TruncateAt.START);
break;
case 2:
setEllipsize(TextUtils.TruncateAt.MIDDLE);
break;
case 3:
setEllipsize(TextUtils.TruncateAt.END);
break;
case 4:
//代码1.1 这个就是设置跑马灯循环效果处
if (ViewConfiguration.get(context).isFadingMarqueeEnabled()) {
setHorizontalFadingEdgeEnabled(true);
mMarqueeFadeMode = MARQUEE_FADE_NORMAL;
} else {
setHorizontalFadingEdgeEnabled(false);
mMarqueeFadeMode = MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS;
}
setEllipsize(TextUtils.TruncateAt.MARQUEE);
break;
}
和跑马灯相关的变量:
private Marquee mMarquee;
private boolean mRestartMarquee;
private int mMarqueeRepeatLimit = 3;
解决方案
直接屏蔽跑马灯动态效果
这种思路最简单,直接将桌面应用的对应id的跑马灯效果的TextView的设置跑马灯效果在方法一中“//代码1.1”处屏蔽。
此方案解决问题简单粗暴,但是这样就彻底将TextView的跑马灯效果全部关闭了,这导致高配置设备也没有此效果,不是一个好的选择。
降低跑马灯移动的速度
跑马灯移动的速度相关逻辑:
方法二:TextView--Marquee--Marquee方法:
Marquee(TextView v) {
final float density = v.getContext().getResources().getDisplayMetrics().density;
//代码2.1 跑马灯移动的速度
mPixelsPerSecond = MARQUEE_DP_PER_SECOND * density;
mView = new WeakReference<TextView>(v);
mChoreographer = Choreographer.getInstance();
}
方法三:TextView--tick方法----TextView界面跑马灯界面刷新
void tick() {
if (mStatus != MARQUEE_RUNNING) {
return;
}
mChoreographer.removeFrameCallback(mTickCallback);
final TextView textView = mView.get();
if (textView != null && (textView.isFocused() || textView.isSelected())) {
long currentMs = mChoreographer.getFrameTime();
long deltaMs = currentMs - mLastAnimationMs;
mLastAnimationMs = currentMs;
//代码3.1 跑马灯移动的速度
float deltaPx = deltaMs / 1000f * mPixelsPerSecond;
mScroll += deltaPx;
if (mScroll > mMaxScroll) {
mScroll = mMaxScroll;
mChoreographer.postFrameCallbackDelayed(mRestartCallback, MARQUEE_DELAY);
} else {
//代码3.2 回调mTickCallback,以循环的实现跑马灯效果
mChoreographer.postFrameCallback(mTickCallback);
}
//代码3.3 textview刷新
textView.invalidate();
}
}
我们调整方法二中 "//代码2.1"和 方法三中"//代码3.1"的跑马灯移动的速度,可以降低跑马灯移动的速度,但是问题仍然存在,也就是说降低跑马灯移动的速度不能降低降低跑马灯效果导致的界面刷新的速度,此方案无效。
降低跑马灯效果界面刷新的速度
那么这个跑马灯效果界面刷新的速度到底是由什么决定的呢?
查看回调方法:
//变量mTickCallback
private Choreographer.FrameCallback mTickCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
//调用界面刷新
tick();
}
};
//变量mStartCallback
private Choreographer.FrameCallback mStartCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
mStatus = MARQUEE_RUNNING;
mLastAnimationMs = mChoreographer.getFrameTime();
//调用界面刷新
tick();
}
};
TextView的跑马灯效果就是通过mStartCallback 回调来循环的调用TextView--tick方法来实现的,且其跑马灯效果界面刷新的速度为每一帧(doFrame)都调用。
其跑马灯循环效果流程为:
那此这就简单了,我的处理方案就是设置一个变量,当变量满足一定条件时(我验证值为10),才调用方法三:TextView--tick方法中的//代码3.3 textview刷新。这样就将跑马灯效果界面刷新的速度降低为原来的十分之一。
测试验证结果
当歌词跑马灯动态显示效果时,设备不卡了,且其traceview的日志调用也是正常的,打开显示面(surface)更新后,界面刷新也不会特别快,问题解决。
标签:动态显示,界面,效果,导致系统,跑马灯,刷新,Android,TextView From: https://blog.51cto.com/u_16502883/9536355