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

【Android】如何查看每个方法所花费的时间从而进行Performance的调优


你是否遇到过这样的情况?

写好一个AP之后,可能你会觉得哪个地方有点卡,可是又不清楚具体卡在哪里?

或者说程序开发到后期我们可以做一些performance tuning的动作来提升AP的用户体验。

那么应该如何查看AP每一执行步骤的耗时呢?Android自带的DDMS里面就可以满足你的需求


下面以之前博客里面的一个小例子分享下如何进行Performance的调优:

【0】程序示例源码:

主程序:

package com.kesen.hoo; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class ActivityMain extends Activity { private MyLogger logger = MyLogger.kLog(); private MyLogger logger2 = MyLogger.jLog(); @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); logger.i("This is log [01]"); setContentView(R.layout.main); Button button = (Button) this.findViewById(R.id.button); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { // TODO Auto-generated method stub logger2.i("This is James action button.OnClick"); } }); } @Override protected void onResume() { // TODO Auto-generated method stub super.onResume(); logger.d("This is kesen log [02]"); } @Override protected void onPause() { // TODO Auto-generated method stub super.onPause(); logger.w("This is kesen log [03]"); } @Override protected void onStop() { // TODO Auto-generated method stub super.onStop(); logger.v("This is kesen log [04]"); } @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); logger.e("This is kesen log [05]"); } }

打印Log的工具类:

package com.kesen.hoo; import java.util.Hashtable; import android.util.Log; /** * The class for print log * @author kesenhoo * */ public class MyLogger { private final static boolean logFlag = true; public final static String tag = "[AppName]"; private final static int logLevel = Log.VERBOSE; private static Hashtable<String, MyLogger> sLoggerTable = new Hashtable<String, MyLogger>(); private String mClassName; private static MyLogger jlog; private static MyLogger klog; private static final String JAMES = "@james@ "; private static final String KESEN = "@kesen@ "; private MyLogger(String name) { mClassName = name; } /** * * @param className * @return */ @SuppressWarnings("unused") private static MyLogger getLogger(String className) { MyLogger classLogger = (MyLogger) sLoggerTable.get(className); if(classLogger == null) { classLogger = new MyLogger(className); sLoggerTable.put(className, classLogger); } return classLogger; } /** * Purpose:Mark user one * @return */ public static MyLogger kLog() { if(klog == null) { klog = new MyLogger(KESEN); } return klog; } /** * Purpose:Mark user two * @return */ public static MyLogger jLog() { if(jlog == null) { jlog = new MyLogger(JAMES); } return jlog; } /** * Get The Current Function Name * @return */ private String getFunctionName() { StackTraceElement[] sts = Thread.currentThread().getStackTrace(); if(sts == null) { return null; } for(StackTraceElement st : sts) { if(st.isNativeMethod()) { continue; } if(st.getClassName().equals(Thread.class.getName())) { continue; } if(st.getClassName().equals(this.getClass().getName())) { continue; } return mClassName + "[ " + Thread.currentThread().getName() + ": " + st.getFileName() + ":" + st.getLineNumber() + " " + st.getMethodName() + " ]"; } return null; } /** * The Log Level:i * @param str */ public void i(Object str) { if(logFlag) { if(logLevel <= Log.INFO) { String name = getFunctionName(); if(name != null) { Log.i(tag, name + " - " + str); } else { Log.i(tag, str.toString()); } } } } /** * The Log Level:d * @param str */ public void d(Object str) { if(logFlag) { if(logLevel <= Log.DEBUG) { String name = getFunctionName(); if(name != null) { Log.d(tag, name + " - " + str); } else { Log.d(tag, str.toString()); } } } } /** * The Log Level:V * @param str */ public void v(Object str) { if(logFlag) { if(logLevel <= Log.VERBOSE) { String name = getFunctionName(); if(name != null) { Log.v(tag, name + " - " + str); } else { Log.v(tag, str.toString()); } } } } /** * The Log Level:w * @param str */ public void w(Object str) { if(logFlag) { if(logLevel <= Log.WARN) { String name = getFunctionName(); if(name != null) { Log.w(tag, name + " - " + str); } else { Log.w(tag, str.toString()); } } } } /** * The Log Level:e * @param str */ public void e(Object str) { if(logFlag) { if(logLevel <= Log.ERROR) { String name = getFunctionName(); if(name != null) { Log.e(tag, name + " - " + str); } else { Log.e(tag, str.toString()); } } } } /** * The Log Level:e * @param ex */ public void e(Exception ex) { if(logFlag) { if(logLevel <= Log.ERROR) { Log.e(tag, "error", ex); } } } /** * The Log Level:e * @param log * @param tr */ public void e(String log, Throwable tr) { if(logFlag) { String line = getFunctionName(); Log.e(tag, "{Thread:" + Thread.currentThread().getName() + "}" + "[" + mClassName + line + ":] " + log + "\n", tr); } } }


Layout文件:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/textview" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> <Button android:id="@+id/button" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello"/> </LinearLayout>


程序跑起来是这样:



【1】如何Trace AP 每一步骤的耗时:

见下图示意,点击开始之后,操作AP开始一些你需要检测的步骤,DDMS已经在记录数据,完成所需要的操作后点击同样的按钮,这个时候Eclipse会自动跳到记录的xxx.trace文件



下面就是自动显示的记录文件,最大化进行查看,请注意我图片上的注解:

这里其实我们可以看到一个AP的启动过程,从什么地方开始调用的,很是方便


上面的圈出的框中我们可以看到ActivityMain的OnCreate的总时间是34个Millisecond(毫秒),再点击SetContentView会看到花了31.423个Millisecond.而且我们有看到Parents与Childrens两个选项,从这个例子中看到OnCreate的主要耗时在于setContensView里面,如果是一个比较复杂的AP,这个Activity的layout元素比较多的,我们会花比较长的时间来做这个步骤,如果你发现这个步骤实在花费时间太多,比如好几百个Miliisecond的时候,我们需要考虑是不是可以把Layout进行优化,尽量减少layout的复杂度,这样会比较好。



写的不好,请多指教,谢谢!


相关文章:

  • docker-compose命令
  • 你还在迭代和递归吗?
  • 受欢迎的牛
  • appium自动化安装(一)
  • Template Method模板方法
  • UVA 10603 倒水问题
  • 程序员编程艺术第二十六章:基于给定的文档生成倒排索引(含源码下载)
  • Flume数据采集准备
  • 【Android】Menu不同菜单的使用介绍
  • python初识
  • Elasticsearch教程收集
  • 巧用Chrome格式化压缩后的js文件
  • 通过LoadBalancerClient获取所有服务列表的IP
  • HPUX Error 23 File table overflow
  • dockerfile 构建tomcat
  • “大数据应用场景”之隔壁老王(连载四)
  • 2017-09-12 前端日报
  • CNN 在图像分割中的简史:从 R-CNN 到 Mask R-CNN
  • codis proxy处理流程
  • css系列之关于字体的事
  • gulp 教程
  • IP路由与转发
  • JavaScript对象详解
  • mysql 数据库四种事务隔离级别
  • PHP 小技巧
  • Quartz实现数据同步 | 从0开始构建SpringCloud微服务(3)
  • session共享问题解决方案
  • Spring Cloud(3) - 服务治理: Spring Cloud Eureka
  • webpack入门学习手记(二)
  • 安卓应用性能调试和优化经验分享
  • 诡异!React stopPropagation失灵
  • 汉诺塔算法
  • 解决iview多表头动态更改列元素发生的错误
  • 微信小程序开发问题汇总
  • Spring Batch JSON 支持
  • #HarmonyOS:基础语法
  • $.proxy和$.extend
  • (32位汇编 五)mov/add/sub/and/or/xor/not
  • (pt可视化)利用torch的make_grid进行张量可视化
  • (ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY)讲解
  • (八)Spring源码解析:Spring MVC
  • (超简单)构建高可用网络应用:使用Nginx进行负载均衡与健康检查
  • (三)centos7案例实战—vmware虚拟机硬盘挂载与卸载
  • (十三)Flask之特殊装饰器详解
  • (学习日记)2024.04.10:UCOSIII第三十八节:事件实验
  • (一)C语言之入门:使用Visual Studio Community 2022运行hello world
  • (转载)OpenStack Hacker养成指南
  • (状压dp)uva 10817 Headmaster's Headache
  • .NET Micro Framework 4.2 beta 源码探析
  • .net 生成二级域名
  • /dev下添加设备节点的方法步骤(通过device_create)
  • @德人合科技——天锐绿盾 | 图纸加密软件有哪些功能呢?
  • [ 常用工具篇 ] AntSword 蚁剑安装及使用详解
  • []利用定点式具实现:文件读取,完成不同进制之间的
  • [8481302]博弈论 斯坦福game theory stanford week 1