怎么检测UI卡顿?(线上及线下)

这篇具有很好参考价值的文章主要介绍了怎么检测UI卡顿?(线上及线下)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

什么是UI卡顿?

在Android系统中,我们知道UI线程负责我们所有视图的布局,渲染工作,UI在更新期间,如果UI线程的执行时间超过16ms,则会产生丢帧的现象,而大量的丢帧就会造成卡顿,影响用户体验。

UI卡顿产生的原因?

  • 在UI线程中做了大量的耗时操作,导致了UI刷新工作的阻塞。
  • 系统CPU资源紧张,APP所能分配的时间片减少。
  • Ardroid虚拟机频繁的执行GC操作,导致占用了大量的系统资源,同时也会导致UI线程的短暂停顿,从而产生卡顿。
  • 代码编写不当,产生了过度绘制,导致CPU执行时间变长,早场卡顿。

从上可知,大部分的卡顿原因都产生于代码编写不当导致,而这类问题都可以通过各种优化方案进行优化,所以我们需要做的就是尽可能准确的找到卡顿的原因,定位到准确的代码模块,最好是能定位到哪个方法导致卡顿,这样我们APP的性能就能得到很大的提升。

UI卡顿方案

  • 开发阶段

在开发阶段我们可以借助开发工具为我们提供的各种便利来有效的识别卡顿,如下:

System Trace

具体使用可以看blog.csdn.net/u011578734/… 写的文章。

Android CPU Profiler

  • Android Studio CPU 性能剖析器可实时检查应用的 CPU 使用率和线程活动。你还可以检查方法跟踪记录、函数跟踪记录和系统跟踪记录中的详细信息。
  • 使用CPU profiler可以查看主线程中,每个方法的耗时情况,以及每个方法的调用栈,可以很方便的分析卡顿产生的原因,以及定位到具体的代码方法。

具体使用方法可以参考 blog.csdn.net/u011578734/…

线上UI卡顿检测方案

线上检测方案比较流行的是BlockCanary和WatchDog,下面我们就看看它们是怎么做到检测UI卡顿的并反馈给开发人员。

BlockCanary

  • BlockCanary能检测到主线程的卡顿, 并将结果记录下来, 以友好的方式展示,很类似于LeakCanary的展示。

BlockCanary的使用很简单,只要在Application中进行设置一下就可以如下:

BlockCanary.install(this, new AppBlockCanaryContext()).start();
  • AppBlockCanaryContext继承自BlockCanaryContext是对BlockCanary中各个参数进行配置的类

可配置参数如下:

//卡顿阀值
int getConfigBlockThreshold();
boolean isNeedDisplay();
String getQualifier();
String getUid();
String getNetworkType();
Context getContext();
String getLogPath();
boolean zipLogFile(File[] src, File dest);
//可将卡顿日志上传到自己的服务
void uploadLogFile(File zippedFile);
String getStackFoldPrefix();
int getConfigDumpIntervalMillis();
  • 在某个消息执行时间超过设定的标准时会弹出通知进行提醒,或者上传。

原理

熟悉Android的Handler机制的同学一定知道,Handler中重要的组成部分,looper,并且应用的主线程只有一个Looper存在,不管有多少handler,最后都会回到这里。 我们注意到Looper.loop()中有这么一段代码:

public static void loop() {
    ...

    for (;;) {
        ...

        // This must be in a local variable, in case a UI event sets the logger
        Printer logging = me.mLogging;
        if (logging != null) {
            logging.println(">>>>> Dispatching to " + msg.target + " " +
                    msg.callback + ": " + msg.what);
        }

        msg.target.dispatchMessage(msg);

        if (logging != null) {
            logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
        }

        ...
    }
}

注意到两个很关键的地方是logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what);logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);这两行代码,它调用的时机正好在dispatchMessage(msg)的前后,而主线程卡也就是在dispatchMessage(msg)卡住了。

BlockCanary的流程图

怎么检测UI卡顿?(线上及线下),性能优化,Android,Framework,ui,移动开发,framework,android,性能优化,面试题

BlockCanary就是通过替换系统的Printer来增加了一些我们想要的堆栈信息,从而满足我们的需求。

替换原有的Printer是通过以下方法:

Looper.getMainLooper().setMessageLogging(mainLooperPrinter);

并在mainLooperPrinter中判断start和end,来获取主线程dispatch该message的开始和结束时间,并判定该时间超过阈值(如2000毫秒)为主线程卡慢发生,并dump出各种信息,提供开发者分析性能瓶颈。如下所示:

@Override
public void println(String x) {
    if (!mStartedPrinting) {
        mStartTimeMillis = System.currentTimeMillis();
        mStartThreadTimeMillis = SystemClock.currentThreadTimeMillis();
        mStartedPrinting = true;
        startDump();
    } else {
        final long endTime = System.currentTimeMillis();
        mStartedPrinting = false;
        if (isBlock(endTime)) {
            notifyBlockEvent(endTime);
        }
        stopDump();
    }
}

private boolean isBlock(long endTime) {
    return endTime - mStartTimeMillis > mBlockThresholdMillis;
}
  • BlockCanary dump的信息包括如下:
基本信息:安装包标示、机型、api等级、uid、CPU内核数、进程名、内存、版本号等
耗时信息:实际耗时、主线程时钟耗时、卡顿开始时间和结束时间
CPU信息:时间段内CPU是否忙,时间段内的系统CPU/应用CPU占比,I/O占CPU使用率
堆栈信息:发生卡慢前的最近堆栈,可以用来帮助定位卡慢发生的地方和重现路径
  • 获取系统状态信息是通过如下代码实现:
threadStackSampler = new ThreadStackSampler(Looper.getMainLooper().getThread(),
            sBlockCanaryContext.getConfigDumpIntervalMillis());
cpuSampler = new CpuSampler(sBlockCanaryContext.getConfigDumpIntervalMillis());

下面看一下ThreadStackSampler是怎么工作的?

protected void doSample() {
//        Log.d("BlockCanary", "sample thread stack: [" + mThreadStackEntries.size() + ", " + mMaxEntryCount + "]");
    StringBuilder stringBuilder = new StringBuilder();

    // Fetch thread stack info
    for (StackTraceElement stackTraceElement : mThread.getStackTrace()) {
        stringBuilder.append(stackTraceElement.toString())
                .append(Block.SEPARATOR);
    }
    // Eliminate obsolete entry
    synchronized (mThreadStackEntries) {
        if (mThreadStackEntries.size() == mMaxEntryCount && mMaxEntryCount > 0) {
            mThreadStackEntries.remove(mThreadStackEntries.keySet().iterator().next());
        }
        mThreadStackEntries.put(System.currentTimeMillis(), stringBuilder.toString());
    }
}

直接去拿主线程的栈信息, 每半秒去拿一次, 记录下来, 如果发生卡顿就显之显示出来 拿CPU的信息较麻烦, 从/proc/stat下面拿实时的CPU状态, 再从/proc/" + mPid + "/stat中读取进程时间, 再计算各CPU时间占比和CPU的工作状态.

基于系统WatchDog原理来实现

  • 启动一个卡顿检测线程,该线程定期的向UI线程发送一条延迟消息,执行一个标志位加1的操作,如果规定时间内,标志位没有变化,则表示产生了卡顿。如果发生了变化,则代表没有长时间卡顿,我们重新执行延迟消息即可。
public class WatchDog {
    private final static String TAG = "budaye";
    //一个标志
    private static final int TICK_INIT_VALUE = 0;
    private volatile int mTick = TICK_INIT_VALUE;
    //任务执行间隔
    public final int DELAY_TIME = 4000;
    //UI线程Handler对象
    private Handler mHandler = new Handler(Looper.getMainLooper());
    //性能监控线程
    private HandlerThread mWatchDogThread = new HandlerThread("WatchDogThread");
    //性能监控线程Handler对象
    private Handler mWatchDogHandler;

    //定期执行的任务
    private Runnable mDogRunnable = new Runnable() {
        @Override
        public void run() {
            if (null == mHandler) {
                Log.e(TAG, "handler is null");
                return;
            }
            mHandler.post(new Runnable() {
                @Override
                public void run() {//UI线程中执行
                    mTick++;
                }
            });
            try {
                //线程休眠时间为检测任务的时间间隔
                Thread.sleep(DELAY_TIME);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //当mTick没有自增时,表示产生了卡顿,这时打印UI线程的堆栈
            if (TICK_INIT_VALUE == mTick) {
                StringBuilder sb = new StringBuilder();
                //打印堆栈信息
                StackTraceElement[] stackTrace = Looper.getMainLooper().getThread().getStackTrace();
                for (StackTraceElement s : stackTrace) {
                    sb.append(s.toString() + "\n");
                }
                Log.d(TAG, sb.toString());
            } else {
                mTick = TICK_INIT_VALUE;
            }
            mWatchDogHandler.postDelayed(mDogRunnable, DELAY_TIME);
        }
    };

    /**
     * 卡顿监控工作start方法
     */
    public void startWork(){
        mWatchDogThread.start();
        mWatchDogHandler = new Handler(mWatchDogThread.getLooper());
        mWatchDogHandler.postDelayed(mDogRunnable, DELAY_TIME);
    }
}
  • 调用startWork即可开启卡顿检测。

为了帮助到大家更好的全面清晰的掌握好性能优化,准备了相关的核心笔记(还该底层逻辑):https://qr18.cn/FVlo89

性能优化核心笔记:https://qr18.cn/FVlo89

启动优化
怎么检测UI卡顿?(线上及线下),性能优化,Android,Framework,ui,移动开发,framework,android,性能优化,面试题
内存优化
怎么检测UI卡顿?(线上及线下),性能优化,Android,Framework,ui,移动开发,framework,android,性能优化,面试题
UI优化
怎么检测UI卡顿?(线上及线下),性能优化,Android,Framework,ui,移动开发,framework,android,性能优化,面试题
网络优化
怎么检测UI卡顿?(线上及线下),性能优化,Android,Framework,ui,移动开发,framework,android,性能优化,面试题
Bitmap优化与图片压缩优化https://qr18.cn/FVlo89
怎么检测UI卡顿?(线上及线下),性能优化,Android,Framework,ui,移动开发,framework,android,性能优化,面试题
多线程并发优化与数据传输效率优化
怎么检测UI卡顿?(线上及线下),性能优化,Android,Framework,ui,移动开发,framework,android,性能优化,面试题
体积包优化
怎么检测UI卡顿?(线上及线下),性能优化,Android,Framework,ui,移动开发,framework,android,性能优化,面试题

《Android 性能监控框架》:https://qr18.cn/FVlo89

怎么检测UI卡顿?(线上及线下),性能优化,Android,Framework,ui,移动开发,framework,android,性能优化,面试题

《Android Framework学习手册》:https://qr18.cn/AQpN4J

  1. 开机Init 进程
  2. 开机启动 Zygote 进程
  3. 开机启动 SystemServer 进程
  4. Binder 驱动
  5. AMS 的启动过程
  6. PMS 的启动过程
  7. Launcher 的启动过程
  8. Android 四大组件
  9. Android 系统服务 - Input 事件的分发过程
  10. Android 底层渲染 - 屏幕刷新机制源码分析
  11. Android 源码分析实战

怎么检测UI卡顿?(线上及线下),性能优化,Android,Framework,ui,移动开发,framework,android,性能优化,面试题文章来源地址https://www.toymoban.com/news/detail-668337.html

到了这里,关于怎么检测UI卡顿?(线上及线下)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 记一次卡顿的性能优化经历实操

    本篇的性能优化不是八股文类的优化方案,而是针对具体场景,具体分析,从排查卡顿根因到一步步寻找解决方案,甚至是规避等方案来最终解决性能问题的经历实操 所以,解决方案可能不通用,不适用于你的场景,但这个解决过程是如何一步步去处理的,解决思路是怎么样

    2024年02月02日
    浏览(29)
  • IDEA性能优化设置(解决卡顿问题)修改内存

    在我们日常使用IDEA进行开发时,可能会遇到许多卡顿的瞬间,明明我们的机器配置也不低啊?为什么就会一直卡顿呢? 原来这是因为IDEA软件在我们安装的时候就设置了默认的内存使用上限(通常很小),这就是造成我们使用IDEA时卡顿的根本原因。比如我这台电脑,明明是

    2023年04月23日
    浏览(45)
  • 线下实体店线上小程序经营的效果如何

    线下实体店尤其是商超便利、鲜花餐饮等行业,本地/外地都可开展生意,然而传统线下信息形式和固定门店拓展范围有限,商家想要线上销售但工具不适,简单的图文/视频效果不佳,无法打通客户消费路径,入驻第三方平台又有抽佣/流量费/客户不属于自己等多种难题。 现

    2024年02月22日
    浏览(30)
  • DockerDesktop性能占用大,优化DockerDesktop占用,DockerDesktop电脑卡顿

    起因 我安装了DockerDesktop,即使不启动容器性能占用明显,电脑不如以前流畅。 启动容器之后,卡顿更加明显。 但是,我使用VMware虚拟机运行Linux,再在里面运行docker,docker里还跑着容器,却不卡,性能占用一般。 于是,我发现是DockerDesktop的问题。 解决 调小一点

    2024年02月11日
    浏览(33)
  • IDEA卡顿,进行性能优化设置(亲测有效)——情况一

    IDEA重新激活后,运行IDEA卡的非常卡顿,没有运行项目,CPU占比也非常高: 可能的原因是,在IDEA的配置中,给他分配的空间比较小 步骤一 选择顶部导航栏中的Help,然后点击Edit Custom VM Options(自定义虚拟机内存)。 点击后,接下来我们将会看到这个界面: 步骤二、我们对其

    2024年04月08日
    浏览(29)
  • 助你加速开发效率!告别IDEA卡顿困扰的性能优化技巧

    在现代软件开发中,IDE(集成开发环境)是一个必不可少的工具。IntelliJ IDEA是一个广受欢迎的IDE,但有时候IDE的性能可能会受到影响,导致开发人员的工作效率降低。本文将介绍一些可以提高IDE性能的技巧,帮助开发人员消除卡顿困扰。 优化IDE的配置 在IDEA中,可以通过修改

    2024年01月25日
    浏览(40)
  • SQL之优化篇:一文搞懂如何优化线上任务性能,增效降本!

    继上一篇文章:SQL优化之诊断篇:快速定位生产性能问题实践。本文将从优化运行时间和优化资源消耗这两个方面,介绍可以提升作业性能的常用方法。 在优化运行时间这个维度上,我们重点关注时间上的加速,单位时间内可能会消耗更多的计算资源。总成本有可能上升,也

    2024年02月10日
    浏览(28)
  • 本地私域线上线下 线上和线下的小程序

    私域商城是一种新型的零售模式,它将传统的线下实体店与线上渠道相结合,通过会员、营销、效率等方式,为消费者提供更加便利和高效的购物体验。私域商城的发展趋势表明,它将成为未来零售业的重要模式,引领零售业的创新和变革。 本地私域线上线下的运营可以结合

    2024年02月03日
    浏览(21)
  • IDEA内存设置,性能优化告别卡顿(JetBrains系列的产品都可以通过这种设置来解决卡顿的问题)

    我们在日常使用时,会出现卡顿的状况,而自己的电脑配置不是很低,这是因为IDEA安装的时候就设置了默认的内存使用上限(通常很小) 以自己的电脑为例,IDEA分配的只有1024MB(1GB),因此会出现卡顿的状况,下面我们进行修改内存。 一、首先我们查看自己电脑IDEA的内存

    2024年02月16日
    浏览(37)
  • iOS UI掉帧和卡顿优化解决方案记录

    UI卡顿原理 在 VSync 信号到来后,系统图形服务会通过 CADisplayLink 等机制通知 App,App 主线程开始在 CPU 中计算显示内容,比如视图的创建、布局计算、图片解码、文本绘制等。随后 CPU 会将计算好的内容提交到 GPU 去,由 GPU 进行变换、合成、渲染。随后 GPU 会把渲染结果提交到

    2024年01月22日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包