当前位置: 首页 > news >正文

网站建设 办公系统国外WordPress小说主题

网站建设 办公系统,国外WordPress小说主题,南康家具网站建设,网站 mssql 数据库一、什么是卡顿#xff1f;或者说我们怎么感知APP卡顿#xff1f; 这里面涉及到android UI渲染机制#xff0c;我们先了解一下android UI是怎么渲染的#xff0c;android的View到底是如何一步一步显示到屏幕上的#xff1f; android系统渲染页面流程#xff1a; 1或者说我们怎么感知APP卡顿 这里面涉及到android UI渲染机制我们先了解一下android UI是怎么渲染的android的View到底是如何一步一步显示到屏幕上的 android系统渲染页面流程 1通过 LayoutInflater 将 View 组件解析成 View 对象对象中封装了组件位置 、显示图片等信息加载到内存中 2CPU 将 View 对象进行计算处理最终得到该组件对应的多维向量图形 ( 使用向量表示的图形 ) 3GPU 接收上述多维向量图形GPU 将该向量图进行栅格化将向量图转为位图 ( 矢量图转为像素图 ) 计算出对应屏幕上每个像素点显示的值将图像数据写入到 Back Buffer 4Android系统每隔大概16.6ms发出VSYNC信号触发对UI进行下一帧的渲染显示屏会使用Frame Buffer跟Back buffer进行交互拿到最新的一帧数据的渲染到屏幕上。 这个渲染过程如果每次渲染都成功就能够达到一个流畅的画面如果16.6ms内CPU和GPU无法处理完一帧画面就会导致Frame Buffer没能交换导致上一帧被重复显示即丢了一帧当丢帧频率越高时用户越能感觉画面卡顿。 这里的16.6ms刷新一帧是由人眼对于每秒60帧的刷新频率感觉是很流畅的计算出来即一帧16.6ms为了能够实现60fps这意味着程序的大多数操作都必须在16ms内完成。  二、SystraceCPU Profiler卡顿分析 Systrace是Android平台提供的一款工具用于记录短期内的设备活动。该工具会生成一份报告其中汇总了Android 内核中的数据例如 CPU 调度程序、磁盘活动和应用线程。Systrace主要用来分析绘制性能方面的问题。在发生卡顿时通过这份报告可以知道当前整个系统所处的状态从而帮助开发者更直观的分析系统瓶颈改进性能。 也可以使用上一节说的CPU Profiler进行卡顿分析CPU Profiler不仅能分析出代码卡顿时间还能精准的定位到代码内容。连接http://t.csdn.cn/WGzhA 三、App层面监控卡顿 目前业界两种主流有效的app监控方式如下 1利用UI线程的Looper打印的日志匹配 2使用Choreographer.FrameCallback。 1、Looper日志检测卡顿 Android主线程更新UI。如果界面1秒钟刷新少于60次即FPS小于60用户就会产生卡顿感觉。简单来说Android使用消息机制进行UI更新UI线程有个Looper在其loop方法中会不断取出message调用其绑定的Handler在UI线程执行。如果在handler的dispatchMesaage方法里有耗时操作就会发生卡顿。 public static void loop() {//......for (;;) {//......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);}//......} } 只要检测 msg.target.dispatchMessage(msg) 的执行时间就能检测到部分UI线程是否有耗时的操作。注意到系统源码的这行代码的执行前后有两个logging.println函数如果设置了logging会分别打印出 Dispatching to和 Finished to 这样的日志这样我们就可以通过两次log的时间差值来计算dispatchMessage的执行时间从而设置阈值判断是否发生了卡顿。这里我们可以自定义LogMonitor并设置到Looper中替换系统的LogMonitor来实现这种方式也是 BlockCanary 的实现原理。 系统Looper和Printer 接口 public final class Looper {private Printer mLogging;public void setMessageLogging(Nullable Printer printer) {mLogging printer;} }public interface Printer {void println(String x); } 自定义BlockCanary public class BlockCanary {public static void install() {LogMonitor logMonitor new LogMonitor();Looper.getMainLooper().setMessageLogging(logMonitor);} } 自定义LogMonitor public class LogMonitor implements Printer {private StackSampler mStackSampler;private boolean mPrintingStarted false;private long mStartTimestamp;// 卡顿阈值private long mBlockThresholdMillis 3000;//采样频率private long mSampleInterval 1000;private Handler mLogHandler;public LogMonitor() {mStackSampler new StackSampler(mSampleInterval);HandlerThread handlerThread new HandlerThread(block-canary-io);handlerThread.start();mLogHandler new Handler(handlerThread.getLooper());}Overridepublic void println(String x) {//从if到else会执行 dispatchMessage如果执行耗时超过阈值输出卡顿信息if (!mPrintingStarted) {//记录开始时间mStartTimestamp System.currentTimeMillis();mPrintingStarted true;mStackSampler.startDump();} else {final long endTime System.currentTimeMillis();mPrintingStarted false;//出现卡顿if (isBlock(endTime)) {notifyBlockEvent(endTime);}mStackSampler.stopDump();}}private void notifyBlockEvent(final long endTime) {mLogHandler.post(new Runnable() {Overridepublic void run() {//获得卡顿时 主线程堆栈ListString stacks mStackSampler.getStacks(mStartTimestamp, endTime);for (String stack : stacks) {Log.e(block-canary, stack);}}});}private boolean isBlock(long endTime) {return endTime - mStartTimestamp mBlockThresholdMillis;} } 自定义StackSampler public class StackSampler {public static final String SEPARATOR \r\n;public static final SimpleDateFormat TIME_FORMATTER new SimpleDateFormat(MM-dd HH:mm:ss.SSS);private Handler mHandler;private MapLong, String mStackMap new LinkedHashMap();private int mMaxCount 100;private long mSampleInterval;//是否需要采样protected AtomicBoolean mShouldSample new AtomicBoolean(false);public StackSampler(long sampleInterval) {mSampleInterval sampleInterval;HandlerThread handlerThread new HandlerThread(block-canary-sampler);handlerThread.start();mHandler new Handler(handlerThread.getLooper());}/*** 开始采样 执行堆栈*/public void startDump() {//避免重复开始if (mShouldSample.get()) {return;}mShouldSample.set(true);mHandler.removeCallbacks(mRunnable);mHandler.postDelayed(mRunnable, mSampleInterval);}public void stopDump() {if (!mShouldSample.get()) {return;}mShouldSample.set(false);mHandler.removeCallbacks(mRunnable);}public ListString getStacks(long startTime, long endTime) {ArrayListString result new ArrayList();synchronized (mStackMap) {for (Long entryTime : mStackMap.keySet()) {if (startTime entryTime entryTime endTime) {result.add(TIME_FORMATTER.format(entryTime) SEPARATOR SEPARATOR mStackMap.get(entryTime));}}}return result;}private Runnable mRunnable new Runnable() {Overridepublic void run() {StringBuilder sb new StringBuilder();StackTraceElement[] stackTrace Looper.getMainLooper().getThread().getStackTrace();for (StackTraceElement s : stackTrace) {sb.append(s.toString()).append(\n);}synchronized (mStackMap) {//最多保存100条堆栈信息if (mStackMap.size() mMaxCount) {mStackMap.remove(mStackMap.keySet().iterator().next());}mStackMap.put(System.currentTimeMillis(), sb.toString());}if (mShouldSample.get()) {mHandler.postDelayed(mRunnable, mSampleInterval);}}}; } 2、Choreographer.FrameCallback检测卡顿 Android系统每隔16ms发出VSYNC信号来通知界面进行重绘、渲染每一次同步的周期约为16.6ms代表一帧的刷新频率。通过Choreographer类设置它的FrameCallback函数当每一帧被渲染时会触发回调FrameCallback.doFrame (long frameTimeNanos) 函数。frameTimeNanos是底层VSYNC信号到达的时间戳 。 public class ChoreographerHelper {public static void start() {if (Build.VERSION.SDK_INT Build.VERSION_CODES.JELLY_BEAN) {Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() {long lastFrameTimeNanos 0;Overridepublic void doFrame(long frameTimeNanos) {//上次回调时间if (lastFrameTimeNanos 0) {lastFrameTimeNanos frameTimeNanos;Choreographer.getInstance().postFrameCallback(this);return;}long diff (frameTimeNanos - lastFrameTimeNanos) / 1_000_000;if (diff 16.6f) {//掉帧数int droppedCount (int) (diff / 16.6);}lastFrameTimeNanos frameTimeNanos;Choreographer.getInstance().postFrameCallback(this);}});}} } 通过 ChoreographerHelper 可以实时计算帧率和掉帧数实时监测App页面的帧率数据发现帧率过低还可以自动保存现场堆栈信息。 Looper比较适合在发布前进行测试或者小范围灰度测试然后定位问题ChoreographerHelper适合监控线上环境的 app 的掉帧情况来计算 app 在某些场景的流畅度然后有针对性的做性能优化。 四、布局优化  1、Layout Inspector层级优化  measure、layout、draw这三个过程都包含自顶向下的View Tree遍历耗时如果视图层级太深自然需要更多的时间来完成整个绘测过程从而造成启动速度慢、卡顿等问题。而onDraw在频繁刷新时可能多次出发因此onDraw更不能做耗时操作同时需要注意内存抖动。 使用Layout Inspector来检查应用的视图层次结构 选择需要查看的进程与Activity在id为content之下的就是我们写在XML中的布局。  排查是否存在Layout的多层嵌套我们应该尽量减少其层级也可以使用 ConstraintLayout 约束布局使得布局尽量扁平化移除非必需的UI组件。  2、使用merge标签  当我们有一些布局元素需要被多处使用时这时候我们会考虑将其抽取成一个单独的布局文件。在需要使用的地方通过 include 加载。  ?xml version1.0 encodingutf-8? LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/androidandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:background#000000android:orientationvertical!-- include layout_merge布局 --include layoutlayout/layout_merge / /LinearLayout !-- layout_merge -- ?xml version1.0 encodingutf-8? LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/androidandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:orientationverticalTextViewandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:background#ffffffandroid:text测试merge / /LinearLayout 这时候我们的主布局文件是垂直的LinearLayoutinclude的 layout_merge 也是垂直的LinearLayout这时候include的布局中使用的LinearLayout就没意义了使用的话反而减慢你的UI表现。这时可以使用merge标签优化。  !-- layout_merge -- merge xmlns:androidhttp://schemas.android.com/apk/res/androidTextViewandroid:background#ffffffandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:text测试merge / /merge 修改为merge后通过LayoutInspector能够发现include的布局中TextView直接被加入到父布局中。  3、使用ViewStub 标签 当我们布局中存在一个View/ViewGroup在某个特定时刻才需要他的展示时可能会把这个元素在xml中定义为invisible或者gone在需要显示时再设置为visible可见。比如在登陆时如果密码错误在密码输入框上显示提示。 1invisible view设置为invisible时view在layout布局文件中会占用位置但是view为不可见该view还是会创建对象会被初始化会占用资源。  2gone view设置gone时view在layout布局文件中不占用位置但是该view还是会创建对象会被初始化会占用资源。  如果view不一定会显示此时可以使用 ViewStub 来包裹此View 以避免不需要显示view但是又需要加载view消耗资源。viewstub是一个轻量级的view它不可见不用占用资源只有设置viewstub为visible或者调用其inflater()方法时其对应的布局文件才会被初始化。  ?xml version1.0 encodingutf-8? LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/androidandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:background#000000android:orientationverticalViewStubandroid:idid/viewStubandroid:layout_width600dpandroid:layout_height500dpandroid:inflatedIdid/textViewandroid:layoutlayout/layout_viewstub / /LinearLayout !-- layout_viewstub -- ?xml version1.0 encodingutf-8? TextView xmlns:androidhttp://schemas.android.com/apk/res/androidandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:background#ffffffandroid:text测试viewStub / 加载viewStub后可以通过 inflatedId 找到layout_viewstub 中的根View。 五、过度渲染  过度绘制是指系统在渲染单个帧的过程中多次在屏幕上绘制某一个像素。例如如果我们有若干界面卡片堆叠在一起每张卡片都会遮盖其下面一张卡片的部分内容。但是系统仍然需要绘制堆叠中的卡片被遮盖的部分。  1、GPU 过度绘制检查 手机开发者选项中能够显示过度渲染检查功能通过对界面进行彩色编码来帮我们识别过度绘制。开启步骤如下 1. 进入开发者选项 (Developer Options)。 2. 找到调试 GPU 过度绘制(Debug GPU overdraw)。 3. 在弹出的对话框中选择显示过度绘制区域Show overdraw areas。  Android 将按如下方式为界面元素着色以确定过度绘制的次数  1. 真彩色没有过度绘制 2. 蓝色过度绘制 1 次 3. 绿色过度绘制 2 次 4. 粉色过度绘制 3 次 5. 红色过度绘制 4 次或更多次  有些过度绘制是不可避免的。在优化应用的界面时应尝试达到大部分显示真彩色或仅有 1 次过度绘制蓝色的视觉效果。  2、解决过度绘制问题 可以采取以下几种策略来减少甚至消除过度绘制 1. 移除布局中不需要的背景 默认情况下布局没有背景这表示布局本身不会直接渲染任何内容。但是当布局具有背景时其有可能会导致过度绘制。移除不必要的背景可以快速提高渲染性能。不必要的背景可能永远不可见因为它会被应用在该视图上绘制的任何其他内容完全覆盖。例如当系统在父视图上绘制子视图时可能会完全覆盖父视图的背景。 2.使视图层次结构扁平化 可以通过优化视图层次结构来减少重叠界面对象的数量从而提高性能。 3.降低透明度 对于不透明的 view 只需要渲染一次即可把它显示出来。但是如果这个 view 设置了 alpha 值则至少需要渲染两次。这是因为使用了 alpha 的 view 需要先知道混合 view 的下一层元素是什么然后再结合上层的 view 进行Blend混色处理。透明动画、淡入淡出和阴影等效果都涉及到某种透明度这就会造成了过度绘制。可以通过减少要渲染的透明对象的数量来改善这些情况下的过度绘制。例如如需获得灰色文本可以在 TextView 中绘制黑色文本再为其设置半透明的透明度值。但是简单地通过用灰色绘制文本也能获得同样的效果而且能够大幅提升性能。 六、布局加载优化  1、异步加载  LayoutInflater加载xml布局的过程会在主线程使用IO读取XML布局文件进行XML解析再根据解析结果利用反射创建布局中的View/ViewGroup对象。这个过程随着布局的复杂度上升耗时自然也会随之增大。Android为我们提供了 Asynclayoutinflater 把耗时的加载操作在异步线程中完成最后把加载结果再回调给主线程。  2、添加依赖  dependencies {implementation androidx.asynclayoutinflater:asynclayoutinflater:1.0.0 } 3、使用AsyncLayoutInflater new AsyncLayoutInflater(this).inflate(R.layout.activity_main, null, new AsyncLayoutInflater.OnInflateFinishedListener() {Overridepublic void onInflateFinished(NonNull View view, int resid, Nullable ViewGroup parent) {setContentView(view);//......}}); 1. 使用异步 inflate那么需要这个 layout 的 parent 的 generateLayoutParams 函数是线程安全的 2. 所有构建的 View 中必须不能创建 Handler 或者是调用 Looper.myLooper因为是在异步线程中加载的异步线程默认没有调用 Looper.prepare 3. AsyncLayoutInflater 不支持设置 LayoutInflater.Factory 或者 LayoutInflater.Factory2 4. 不支持加载包含 Fragment 的 layout 5. 如果 AsyncLayoutInflater 失败那么会自动回退到UI线程来加载布局。
http://www.huolong8.cn/news/425382/

相关文章:

  • 网站推广公司 优帮云安全员资格证书查询网
  • 在网站后台挂马如何自己建网站
  • 专注网站基础优化seo整站优化方案案例
  • 合肥做百度网站网站建设涉及的内容
  • 湘潭做网站的公司手表二级市场网站
  • 惠州网站建设公司排名电子商城网站开发文档
  • 网站代备案公司我有一个网站怎么做外贸
  • 六安网站排名优化电话平台公司是什么意思
  • 个人做网站哪种类型的网站好photoshop网站模板设计教程视频
  • 关键词查询爱站网天元建设集团有限公司北京分公司
  • 做美图+网站有哪些网站建设用图
  • 网站建设都是用什么软件海南建设网网站
  • 淄博哪里有网站建设平台自己做网站上市
  • 北京网站建设公司飞沐郑州做网站建设的公司
  • 去哪里找人做网站湖北建设局网站首页
  • 锦州网站建设信息广州seo优化外包服务
  • 临安市建设局网站wordpress访问地址修改
  • 门图书馆户网站建设方案湖南seo优化推荐
  • 自学软件网站开发如何制作香水 简单
  • cdn 加速 网站郑州新闻最新消息今天
  • 域名解析网站网络规划与设计第二版
  • python做网站内容爬虫网站正在建设中 源码
  • 秦皇岛建设管理中心网站优秀的个人网站设计
  • 手机网站设计规范嘉兴网站推广
  • 兰州网络公司网站深圳互联网
  • 我要建设公司网站网站开发设计技术
  • 哪里可以上传自己的php网站wordpress 滑动相册
  • 廊坊网站建设推广服务做网站推广代理
  • 集团网站建设案例与网站作用wordpress百度和分类
  • 个人交互式网站备案淄博微网站建设