【Android】如何檢視每個方法所花費的時間從而進行Performance的調優

iteye_20954發表於2011-12-27


你是否遇到過這樣的情況?

寫好一個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的複雜度,這樣會比較好。



寫的不好,請多指教,謝謝!


相關文章