編輯:關於Android編程
一款Android商業應用上線後,最關心的莫過於用戶使用哪個模塊比較頻繁,哪個模塊使用人群較少,產品可以根據這些數據來修正app以後的發展方向,使產生最大的商業價值。
通過埋點監控,我們可以深入業務的每一個細節,產生的用戶行為可以通過所埋的點累計次數並將這些數據發送到數據中心,通過數據分析師就能給產品提出寶貴的意見,指導產品的演化方向。
本文基於我的上一篇博客Android 事件分發機制詳解,如果你對事件分發機制不是特別了解的話,建議先去看一下這篇文章。
我們的埋點方案要做到以下功能:
設計思路大體如下:
利用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工具來舉一個實例。
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的目錄下,一段時間後(這個自定義)開啟新線程,將用戶行為信息傳送到後台服務器,這個步驟比較簡單,就不上源碼了。
Android studio 出現 Unsupported major.minor version 52.0解決辦法 最近更新了Android studio
我們在完整編譯android系統的時候,最終會生成幾個重要的鏡像文件,其中有system.img,userdata.img,ramdisk.img等。這篇文章的目的是分析
前言經過幾年的發展和沉澱,Android開發中湧現出許多優秀的框架,比如:Retrofit、Afinal、OKHttp、ButterKnife、AndFix等等。這些框架
今天在Android Studio中把另外一個項目引入當前項目,編譯的時候出現了java.util.zip.ZipException: duplicate entry錯誤