Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android應用中埋點監控的思考與設計

Android應用中埋點監控的思考與設計

編輯:關於Android編程

 

 

一款Android商業應用上線後,最關心的莫過於用戶使用哪個模塊比較頻繁,哪個模塊使用人群較少,產品可以根據這些數據來修正app以後的發展方向,使產生最大的商業價值。

通過埋點監控,我們可以深入業務的每一個細節,產生的用戶行為可以通過所埋的點累計次數並將這些數據發送到數據中心,通過數據分析師就能給產品提出寶貴的意見,指導產品的演化方向。

本文基於我的上一篇博客Android 事件分發機制詳解,如果你對事件分發機制不是特別了解的話,建議先去看一下這篇文章。

綜述設計方案

我們的埋點方案要做到以下功能:

  1. Android界面上的空間被用戶點擊,需要記錄下點擊控件的名稱並保存此信息。
  2. Android界面被打開或關閉,也需要記錄此信息
  3. 最好能自動化完成,不需要修改大量代碼,最好能定制

    設計思路大體如下:

    1. 設計一個基類BaseActivity,它是繼承自Activity,但是覆寫了Activity的幾個方法(後面會詳細說明)。
    2. 利用廣播來統一管理用戶行為的Log信息。
    3. 數據積累到一定量,將用戶行為數據發送到後台服務器。

      BaseActivity基類的設計

      利用Android事件分發機制,我們自定義的基類BaseActivity繼承自Activity並重寫Activity的dispatchTouchEvent方法(為什麼要這麼做?還請參考我的上一篇博客),以及重寫Activity的所有生命周期方法。

      重寫Activity的生命周期以及事件分發方法

      重寫Activity生命周期的onStart()和onStop(){或者onDestory,這個根據自己的選擇確定},來完成對界面開啟和關閉的埋點記錄。事件分發方法來檢測ACTION_UP這個事件(也就是手指觸動觸摸屏抬起的那個事件),二者通過本地廣播,將onStart或onStop這些事件廣播出來並被接收處理。

       1 public class BaseActivity extends Activity {
       2  protected void onStart(){
       3      super.onStart();
       4      // 使用本地廣播,高效更安全
       5      LoacalBroadcastManager bcManager = LocalBroadcastManager.getInstance(this);
       6      Intent intent = new Intent(ACTIVITY_START);//自定義的ACTIVITY_START
       7      bcManager.sendBroadcast(intent);
       8  }        
       9  protected void onStop(){
      10      super.onStop();
      11      LoacalBroadcastManager bcManager = LocalBroadcastManager.getInstance(this);
      12      Intent intent = new Intent(ACTIVITY_STOP);//自定義的ACTIVITY_STOP
      13      bcManager.sendBroadcast(intent);
      14  }
      15  //.......可擴展
      16  protected boolean dispatchTouchEvent(MotionEvent e){
      17      if (e.getAction() == MotionEvent.ACTION_UP){
      18          LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(this);
      19             Intent intent = new Intent(VIEW_CLICK);
      20             intent.putExtra(VIEW_CLICK, e);
      21             broadcastManager.sendBroadcast(intent);
      22      }
      23  }

      廣播事件的處理

      在處理廣播的事件類中,我們獲得VIEW_CLICK的Action就開始遍歷當前Activity中所有的View,通過比對點擊事件event的坐標個View的坐標,來判斷是點擊哪個View的event。

       1 public class BaseActivity extends Activity {
       2  //.......
       3  public class MonitorUserReceiver extends BroadcastReceiver {
       4      public void onReceive(Context context, Intent intent) {
       5          String action = intent.getAction();
       6          switch(action){
       7              case VIEW_CLICK:
       8                  MotionEvent event = intent.getParcelableExtra(VIEW_CLICK);
       9                  //遞歸遍歷Activity中的所有View,找出被點擊的View
      10                  View clickView = searchClickView(view, event);
      11                  //獲取clickView的路徑信息
      12                  //生成log記錄下來
      13                  Log.writeLog();
      14                  break;
      15              case ACTIVITY_START:
      16                  //可以知道某個界面被打開了,然後記錄此次操作行為
      17                  Log.writeLog();
      18                  break;
      19              case ACTIVITY_STOP:
      20                  Log.writeLog();
      21                  break;
      22              //可擴展...
      23          }
      24      }
      25      private View searchClickView(View view, MotionEvent event) {
      26          View clickView = null;
      27          if (isInView(view, event) && 
      28              view.getVisibility() == View.VISIBLE) {  //當前View必須是可見的
      29              if (view instanceof ViewGroup) {   //如果是類似Layout的ViewGroup,繼續遍歷它下面的子View
      30                  ViewGroup group = (ViewGroup) view;
      31                  for (int i = group.getChildCount() - 1; i >= 0; i--) {
      32                      View childView = group.getChildAt(i);
      33                      clickView = searchClickView(childView, event);
      34                      if (clickView != null) {
      35                          return clickView;
      36                      }
      37                  }
      38              }
      39              clickView = view;
      40          }    
      41          return clickView;
      42      }
      43      public boolean isInView(View view,MotionEvent event){
      44          int clickX = event.getRawX();    //獲取點擊事件的X和Y坐標
      45          int clickY = event.getRawY();
      46          //如下的view表示Activity中的子View或者控件
      47          int[] location = new int[2];  
      48          view.getLocationOnScreen(location);  
      49          int x = location[0];
      50          int y = location[1];
      51          int width = view.getWidth();
      52          int height = view.getHeight();
      53          if (clickX < x || clickX > (x + width) || 
      54              clickY < y || clickY > (y + height)) {
      55              return true;  //此條件成立,說明這個view被點擊了
      56          }
      57          return false;
      58      }    
      59  }

      記錄View的路徑

      上面代碼中提到要記錄View的路徑,我們可以通過給空間加Tag的方式,給此view空間位移的名字或ID,但一個Android app中的控件數量太多,想都加上Tag實在太麻煩,並且有漏加的風險。

      Activity中的UI是層層嵌套的,其中根布局是PhoneWindow$DecorView,下面通過hierarchyviewer工具來舉一個實例。

      monitZ喎?/kf/ware/vc/vclVzZXIwMQ==" src="/uploadfile/Collfiles/20141011/2014101108335438.png" />

      上圖有一個TextView,如果按照我的采用的是View控件的路徑方式標識方法應該是:

      DecorView[0]>ActionBarOverlayLayout[0]>FrameLayout[0]>RelativeLayout[0]>TextView [0]:helloworld

      在此路徑前加上Activity的名字,便構成了控件View唯一的屬性標識。例如我們在DemoActivity裡有一個button,button名字為hello:

      DemoActivity:DecorView[0]>ActionBarOverlayLayout[0]>FrameLayout[0]>RelativeLayout[0]>Button [0]:hello

      DecorView,可通過this.getWindow().getDecorView()獲得。其實在searchClickView方法中我們可以加上路徑,找到我們需要的View,那麼當前這個路徑自然就知道了。 這種方法產生的問題有:產生的路徑是:

      DecorView>ActionBarOverlayLayout>FrameLayout>RelativeLayout>Button:helloworld

      當有一個重名的Button時,根本分不清楚到底是哪一個Button。要是我們能產生類似DemoActivity:DecorView[0]>ActionBarOverlayLayout[0]>FrameLayout[0]>RelativeLayout[0]>Button [0]:hello 這種路徑,就能完美解決這個問題了。所以需要去看 hierarchyviewer工具的源代碼,看看它是怎麼做到的。要是有讀者分析過hierarchyviewer的源代碼,歡迎交流該怎麼獲得這個路徑。

      將用戶行為信息傳到後台服務器

      用戶點擊的log信息,我們可以用XML或JSON來格式化數據,然後存到app的目錄下,一段時間後(這個自定義)開啟新線程,將用戶行為信息傳送到後台服務器,這個步驟比較簡單,就不上源碼了。

      不足之處

      1. 當前的APP使用這種DemoActivity:DecorView>ActionBarOverlayLayout>FrameLayout>RelativeLayout>Button:helloworld絕對路徑,盡管app初期比較簡單,但是若有工程師不注意使用相同的名字控件,會出現找到第一個就返回情況,後期還要繼續研究hierarchyviewer的源代碼,找到使用絕對路徑的方法。
      2. 兩個Button重疊,點擊此Button,可能無法找到正確的一個,這個問題暫時沒想出如何解決,只能靠工程師小心,不要加入重疊的Button。
        更多內容請參照我的個人站點: http://stackvoid.com/
         
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved