Android布局优化

  • 16ms 发出Vsync信号触发UI渲染
  • Android设备屏幕刷新频率值:60Hz

工具选择

Systrace

  • 关注Frames
  • 正常绿色 ,丢帧黄色或者红色
  • Alerts栏 会有修改建议

Layout Inspector 查看控件层级

  • Android studio工具栏Tools - Layout Inspector

Choreographer 获取fps

  • 获取FPS ,线上使用 ,具备实时性
  • API 16+
    private long mStartFrameTime = 0;
    private int mFrameCount = 0;
    private static final long MONITOR_INTERVAL = 160L; //单次计算FPS使用160毫秒
    private static final long MONITOR_INTERVAL_NANOS = MONITOR_INTERVAL * 1000L * 1000L;
    private static final long MAX_INTERVAL = 1000L; //设置计算fps的单位时间间隔1000ms,即fps/s;
  @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    private void getFPS() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
            return;
        }
        Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() {
            @Override
            public void doFrame(long frameTimeNanos) {
                if (mStartFrameTime == 0) {
                    mStartFrameTime = frameTimeNanos;
                }
                long interval = frameTimeNanos - mStartFrameTime;
                if (interval > MONITOR_INTERVAL_NANOS) {
                    double fps = (((double) (mFrameCount * 1000L * 1000L)) / interval) * MAX_INTERVAL;
                    mFrameCount = 0;
                    mStartFrameTime = 0;
                } else {
                    ++mFrameCount;
                }

                Choreographer.getInstance().postFrameCallback(this);
            }
        });
    }

Android 布局加载原理

View的最终创建流程

  • 导致布局性能的原因
    • 布局文件解析 : IO过程
    • 创建View对象 : 反射
    • 过度绘制
  • LayoutInflater.Factory
    • LayoutInflater创建View的一个Hook
    • 定制创建View的过程
  • Factory2 extend Factory
    • onCreateView多了一个parent

获取layout界面布局耗时

AOP方式 - AspectJ

  • 切Activity的setContentView

@Around(“execution(*android.app.Activity.setContentView(…))”)

// call        切在方法调用的位置
// execution   切在方法执行的里面
@Around("execution(* android.app.Activity.setContentView(..))")
    public void getSetContentViewTime(ProceedingJoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        String name = signature.toShortString();
        long time = System.currentTimeMillis();
        try {
            joinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        LogUtils.i(name + " cost " + (System.currentTimeMillis() - time));
    }

ARTHook实现

获取layout里面单个view的耗时时间

  • 在 super.onCreate(savedInstanceState);之前
 LayoutInflaterCompat.setFactory2(getLayoutInflater(), new LayoutInflater.Factory2() {
            @Override
            public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
				// 全局更改TextView效果,LayoutInflater是一种Hook
                if (TextUtils.equals(name, "TextView")) {
                    // 生成自定义TextView
                }
                long time = System.currentTimeMillis();
                View view = getDelegate().createView(parent, name, context, attrs); //view控件创建完成
                LogUtils.i(name + " cost " + (System.currentTimeMillis() - time));
                return view;
            }

            @Override
            public View onCreateView(String name, Context context, AttributeSet attrs) {
                return null;
            }
        });
       super.onCreate(savedInstanceState);

AsyncLayoutInflater 异步Inflat

原因
  • xml解析 ,IO流操作
  • 反射创建View,比直接new慢3倍
方案
  • WorkThred加载布局 ,布局加载完成回调主线程渲染
  • implementation ‘com.android.support:asynclayoutinflater:28.0.0-alpha1’
new AsyncLayoutInflater(MainActivity.this).inflate(R.layout.activity_main, null, new AsyncLayoutInflater.OnInflateFinishedListener() {
            @Override
            public void onInflateFinished(@NonNull View view, int i, @Nullable ViewGroup viewGroup) {
                setContentView(view);
                // todo findViewById(id);
                TextView tv =  findViewById(R.id.tv);
            }
        });

X2C 优化布局

  • View兼容性不好,部分api不存在不推荐使用
  • APT编译器翻译xml为java代码
  • annotationProcessor ‘com.zhangyue.we:x2c-apt:1.1.2’
  • implementation ‘com.zhangyue.we:x2c-lib:1.0.6’
  • @Xml(layouts = “activity_main”) 类注解 layout文件名
  • X2C.setContentView(MainActivity.this,R.layout.activity_main); 替换 setContentView(view);

视图绘制

  • 流程
    • 测量
    • 布局
    • 绘制
  • 性能瓶颈
    • 每个阶段都耗时
    • View层级太多
    • 绘制创建对象过多,计算过于耗时等
  • 布局层级优化
    • 优先选用ConstraintLayout布局
    • merge标签使用,只能用于根布局,限制性较大
  • 过度绘制优化
    • 去掉多余的背景,减少shaoe的使用
    • 控件叠加
    • 自定义控件开发时, 使用clipRect屏蔽被遮盖的布局
    • 开发者选项打开 “调试GPU过度绘制”
  • 其它技巧
    • Viewstub :占位符,延迟初始化
      • 不参与测量,布局,绘制过程
    • onDraw(): 避免绘制太大对象
    • TextView效率低,可以针对TextVIew优化
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值