Android开发

Android高手笔记-屏幕适配 & UI优化

2023-09-19  本文已影响0人  进击的老六

屏幕与适配

  1. 在不同尺寸及分辨率上UI的一致(影响着用户体验);

  2. 从效果图到UI界面代码的转化效率(影响着开发效率);

适配方式:

px

dp

  1. 只能适配大部分手机(也做不到和效果图的完全一致),某些特殊机型仍需单独适配(比如同样1920*1080的手机的dpi却可能不同);

  2. 设计稿到布局代码的实现效率低(设计稿的宽高和手机屏幕的宽高不同,px和dp间的转换,往往需要百分比或估算等,会极大地拉低开发效率);

宽高限定符适配

鸿洋的AndroidAutoLayout适配方案等动态计算UI适配框架

smallestWidth适配 或者叫sw限定符适配

今日头条适配方案

  1. DisplayMetrics.density 就是上述的density;

  2. DisplayMetrics.densityDpi 就是上述的dpi;

  3. DisplayMetrics#scaledDensity 字体的缩放因子,正常情况下和density相等,但是调节系统字体大小后会改变这个值;

UI优化

CPU 与 GPU

OpenGL 与 Vulkan

1. 画笔:Skia 或者 OpenGL。我们可以用 Skia 画笔绘制 2D 图形,也可以用 OpenGL 来绘制 2D/3D 图形。正如前面所说,前者使用 CPU 绘制,后者使用 GPU 绘制。  
2. 画纸:Surface。所有的元素都在 Surface 这张画纸上进行绘制和渲染。在 Android 中,Window 是 View 的容器,每个窗口都会关联一个 Surface。  
而 WindowManager 则负责管理这些窗口,并且把它们的数据传递给 SurfaceFlinger。  
3. 画板:Graphic Buffer。Graphic Buffer 缓冲用于应用程序图形的绘制,在 Android 4.1 之前使用的是双缓冲机制;在 Android 4.1 之后,使用的是三缓冲机制。  
4. 显示:SurfaceFlinger。它将 WindowManager 提供的所有 Surface,通过硬件合成器 Hardware Composer 合成并输出到显示屏。  

Android 渲染的演进

  1. 在 Android 3.0 之前,或者没有启用硬件加速时,系统都会使用软件方式来渲染 UI;

  2. Androd 3.0 开始,Android 开始支持硬件加速;

  3. Android 4.0 时,默认开启硬件加速;

  4. Android 4.1:

  1. 开启了Project Butter: 主要包含两个组成部分,一个是 VSYNC,一个是 Triple Buffering。VSYNC信号:对于 Android 4.0,CPU 可能会因为在忙别的事情,导致没来得及处理 UI 绘制。为解决这个问题,Project Buffer 引入了VSYNC,它类似于时钟中断。每收到 VSYNC 中断,CPU 会立即准备 Buffer 数据,由于大部分显示设备刷新频率都是 60Hz(一秒刷新 60 次),也就是说一帧数据的准备工作都要在 16ms 内完成。三缓冲机制 Triple Buffering:Android 4.1 之前,Android 使用双缓冲机制,CPU、GPU 和显示设备都能使用各自的缓冲区工作,互不影响

  2. Android 4.1还新增了 Systrace 性能数据采样和分析工具。

  3. Tracer for OpenGL ES 也是 Android 4.1 新增加的工具,它可逐帧、逐函数的记录 App 用 OpenGL ES 的绘制过程。它提供了每个 OpenGL 函数调用的消耗时间,所以很多时候用来做性能分析。但因为其强大的记录功能,在分析渲染问题时,当 Traceview、Systrace 都显得棘手时,还找不到渲染问题所在时,此时这个工具就会派上用场了。

  1. Android 4.2,系统增加了检测绘制过度工具;

  2. Android 5.0:RenderThread:

  1. Android 6.0 ,在 gxinfo 添加了更详细的信息;

  2. 在 Android 7.0 又对 HWUI 进行了一些重构,而且支持了 Vulkan;

  3. 在 Android P 支持了 Vulkun 1.1。

UI 渲染测量

1. gfxinfo

2. SurfaceFlinger

获取界面布局耗时

  1. AOP
@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();  
    }  
    LogHelper.i(name + " cost " + (System.currentTimeMillis() - time));  
}  

  1. LayoutInflaterCompat.setFactory2
@Override  
protected void onCreate(@Nullable Bundle savedInstanceState) {  
  
    // 使用LayoutInflaterCompat.Factory2全局监控Activity界面每一个控件的加载耗时,  
    // 也可以做全局的自定义控件替换处理,比如:将TextView全局替换为自定义的TextView。  
    LayoutInflaterCompat.setFactory2(getLayoutInflater(), new LayoutInflater.Factory2() {  
        @Override  
        public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {  
  
            if (TextUtils.equals(name, "TextView")) {  
                // 生成自定义TextView  
            }  
            long time = System.currentTimeMillis();  
            // 1  
            View view = getDelegate().createView(parent, name, context, attrs);  
            LogHelper.i(name + " cost " + (System.currentTimeMillis() - time));  
            return view;  
        }  
  
        @Override  
        public View onCreateView(String name, Context context, AttributeSet attrs) {  
            return null;  
        }  
    });  
  
    // 2、setFactory2方法需在super.onCreate方法前调用,否则无效  
    super.onCreate(savedInstanceState);  
    setContentView(getLayoutId());  
    unBinder = ButterKnife.bind(this);  
    mActivity = this;  
    ActivityCollector.getInstance().addActivity(this);  
    onViewCreated();  
    initToolbar();  
    initEventAndData();  
}  
  

UI优化的常用手段

1. 尽量使用硬件加速

2. Create View 优化

  1. 不能设置LayoutInflater.Factory,需要通过自定义AsyncLayoutInflater的方式解决,由于它是一个final,所以需要将代码直接拷处进行修改。

  2. 因为是异步加载,所以需要注意在布局加载过程中不能有依赖于主线程的操作。

3. measure/layout 优化

上一篇下一篇

猜你喜欢

热点阅读