专项优化

专项优化

列表页卡顿优化

  • 常规方案

    • ListView 复用View
    • getView 相关方法中有耗时操作,要采用异步处理
  • RecycleView 优化

  • 布局相关

    • 减少布局层级、避免过度绘制
    • 采用异步 inflate 或者 X2C
  • 图片相关

    • 避免过大尺寸:GC 频繁、内存抖动
    • 滑动时取消加载
  • 合理使用线程池,避免主线程被过度抢占

  • TextView 优化

    原因:面对复杂文本性能不佳,BoringLayout 单行、StaticLayout 多行、DynamicLayout 可编辑

    • 展示类使用 StaticLayout 即可,性能优于 DynamicLayout

    • 异步创建 StaticLayout

    • 也可使用 TextLayoutBuilder 替换原 TextView

    • 也还可以使用 google 在 Android 9.0 提供的 PrecomputedText

      1
      2
      3
      Future<PrecomputedTextCompat> future = PrecomputedTextCompat.getTextFuture(
      “text”, textView.getTextMetricsParamsCompat(), null);
      textView.setTextFuture(future);
  • 要留意字符串的拼接【备注:貌似编译器会自动转成 StringBuilder 进行 append

存储优化

  • 常规方案

    • 确保 IO 操作发生在子线程
  • SharePreferences 相关

    • 加载慢:初始化时会加载整个文件到内存中,虽然加载放在了异步线程,但是内部加锁,同样有 UI 线程等待异步线程的情况
    • 全量写入:每次改动都会导致整体写入,无论改动的内容有多少
    • 卡顿:Android 系统补偿策略导致,为了保证数据不会丢失,如在界面销毁时会进行一次全量保存,如果该操作执行时间较长,有可能出现卡顿、ANR 的情况
    • 【一定要使用时】调优:尽可能的存储小文件,按业务区分模块存储来拆分文件,key可以考虑使用数值来替换长字符串来减少文件大小
    • 【替换方案】MMKV:支持跨进程,通过mmap和文件锁保证数据完整性,支持增量写入、使用 Protocol Buffer,性能和安全性都优于SP
  • 日志存储优化

    要做到不影响性能、日志不丢失、安全

    • 常规实现一:每产生一个日志都写一遍到磁盘中,每次都会有IO产生,不丢失有性能损耗
    • 常规实现二:通过 StringBuilder 开辟一个内存,先存 buffer,再存文件,性能较优有丢日志可能
    • 推荐方案:使用 mmap,内存映射文件,参考 loggerXlogLogan
  • 其它

    • 常用数据缓存,避免多次读取
    • 合理设置缓冲区Buffer大小:4-8KB

WebView 异常监控

WebView 版本众多以及对接的业务方众多,出现异常的概率比较大

  • 资源释放

    WebView 占用资源问题,在应用中只要使用一次WebView,资源就不能完全释放掉而占用内存。

    解决方案:

    为 WebView 开启一个独立的进程,使用 AIDL 通信,WebView 所在进程根据业务的需要在合适的时机进行销毁,达到正常释放内存的目的

  • 异常监控思路

    • 监控屏幕是否白屏,白屏则有问题,所有像素都是同一颜色的则认为时白屏

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      /**
      * 判断Bitmap是否都是一个颜色
      * @param bitmap
      * @return
      */
      public static boolean isBlank(View view) {
      Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
      Canvas canvas = new Canvas(bitmap);
      view.draw(canvas);

      if (bitmap == null) {
      return true;
      }
      int width = bitmap.getWidth();
      int height = bitmap.getHeight();
      if (width > 0 && height > 0) {
      int originPix = bitmap.getPixel(0, 0);
      int[] target = new int[width];
      Arrays.fill(target, originPix);
      int[] source = new int[width];
      boolean isWhiteScreen = true;
      for (int col = 0; col < height; col++) {
      bitmap.getPixels(source, 0, width, 0, col, width, 1);
      if (!Arrays.equals(target, source)) {
      isWhiteScreen = false;
      break;
      }
      }
      return isWhiteScreen;
      }
      return false;
      }