上一篇文章中我們介紹了android社區中比較火的熱修復功能,并介紹了目前的幾個比較流行的熱修復框架,以及各自的優缺點,同時也介紹了一下自身項目中對熱修復功能的實踐。目前主流的熱修復原理上其實分為兩種,一種是通過利用dex的加載順序實現熱修復功能,一種是通過native層實現指針替換實現熱修復功能,兩種各有利弊可以根據自身產品的需要選擇不同的方案。具體可參考: [Android產品研發(七)–>Apk熱修復](http://blog.csdn.net/qq_23547831/article/details/51587927)。
而文本將要介紹一下android產品中另一項基礎功能-數據統計。App數據統計的意義在于通過統計用戶的行為方式有針對性的更新展示算法,根據用戶的行為習慣更新產品功能等等,具體而言當我們開發好App后就會把它發到應用市場上,但是目前有很多的應用市場(如,豌豆莢,應用寶,安卓市場等),那么問題來了,假如我們想統計我們開發的應用的下載次數,就必須使用統計吧,而且它不僅可以統計我們的應用的下載量,啟動次數,還可以統計頁面訪問量、查看程序的bug等等,所以相對于項目而言產品由于存在著持續的迭代與用戶體驗,所以做好數據統計工作是一項必不可少的工作。
本文中數據統計主要介紹兩種:第三方統計服務和自己實現數據統計功能。
相對而言這兩種方式各有利弊,第三方統計服務簡單、方便、統計范圍廣,但是數據保存在第三方,對于一些數據比較敏感的App可能不太喜歡這種方式,而自己實現數據統計功能主要優點就是安全可定制化,當然了缺點也是顯而易見的,就是繁瑣,復雜。
下面我分別就這兩種數據統計方式做一下簡單的介紹。
**第三方統計服務**
一般情況下App中都是使用第三方數據統計服務的,友盟、百度統計等等,這里簡單介紹一下友盟統計,其余的都是大同小異。
[友盟統計官網 ](http://mobile.umeng.com/)
友盟統計中不但有統計相關功能,還提供了錯誤分析,社會化分享,推送,即時通訊等等,當然這里我們重點分析的是其數據統計功能。
在友盟官網中我們可以看到其對統計服務的介紹,這里我們大概的看一下:

可以發現我們提供了用戶統計,渠道統計,頁面訪問路徑統計,點擊事件統計等等。
那么我們如何才能繼承友盟的統計功能的,其在SDK文檔介紹中已經做了詳細介紹,大概的集成流程是下載友盟SDK jar包,然后引用,并在相應的Activity/Fragment的生命周期方法中調用相關的API。
**自己實現數據統計功能**
對于一些數據敏感的App來說可能自己實現部分數據統計功能是一個比較不錯的選擇,當初筆者也做過類似的功能,其原理就是參考友盟的數據統計在App打開的時候執行數據上報功能。
這里簡單介紹一下自己實現的數據統計功能的流程:
(1)數據統計上報主要分為兩中方式,網絡請求上報和文件信息上報;
(2)網絡請求上報就是直接調用網絡請求若請求失敗,則將上報信息保存至本地文件中;
(3)本地上報文件設置闕值和間隔時間,若距離上次上報時間大于闕值或者是文件大小大于闕值則執行上報操作,若上報成功則刪除本地數據文件;
(4)本地數據文件在上報之前有加密和壓縮操作;
(5)在App打開的時候執行一次數據上報操作,在特定的操作下可以執行上報操作;
(6)上報操作是在Service服務中執行,避免上報操作被由于進程被殺死而中斷;
最后貼上為了實現數據上報而自定義的數據統計服務:
~~~
/**
* Created by aaron on 2016/4/8.
* desc:UU打點service
*/
public class UUPointService extends Service {
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
/**
* desc:該service為APP打點service
* 主要實現兩個后臺服務:
* (1)內存數據上報;
* (2)文件數據上報;
*/
if (intent != null && intent.getStringExtra(UUPoint.LOADTYPE) != null && intent.getStringExtra(UUPoint.LOADTYPE).trim().equals(UUPoint.LOADDATA)) {
if (UUPoint.writeMap.size() > 0) {
//(1)轉換數據
final List<String> strList = new ArrayList<String>();
Iterator<Map.Entry<String, Integer>> iterator = UUPoint.writeMap.entrySet().iterator();
while (iterator.hasNext()) {
StringBuffer sb = new StringBuffer();
Map.Entry<String, Integer> entry = iterator.next();
String key = entry.getKey();
Integer count = entry.getValue();
sb.append(key).append(",").append(count);
strList.add(sb.toString());
}
if (strList.size() > 0) {
// 上傳服務器數據上傳服務器數據
SystemCommon.ReportLogBatch.Builder builder = SystemCommon.ReportLogBatch.newBuilder();
builder.addAllLogLine(strList);
SystemInterface.ReportLogInfoRequest.Builder request = SystemInterface.ReportLogInfoRequest.newBuilder();
request.setLogData(ByteString.copyFrom(GZipUtils.compress(builder.build().toByteArray())));// 壓縮數據包
NetworkTask task = new NetworkTask(CmdCodeDef.CmdCode.ReportLogInfo_VALUE);
task.setBusiData(request.build().toByteArray());
NetworkUtils.executeNetwork(task, new HttpResponse.NetWorkResponse<UUResponseData>() {
@Override
public void onSuccessResponse(UUResponseData responseData) {
if (responseData.getRet() == 0) {
try {
SystemInterface.ReportLogInfoResponse response = SystemInterface.ReportLogInfoResponse.parseFrom(responseData.getBusiData());
if (response.getRet() == 0) {
/*MLog.i("tab", "########################");
for (String str : strList) {
MLog.i("tab", str);
}*/
UUPoint.writeMap.clear();
UUPointUtils.setLastPointTime(UUPointService.this);
/*MLog.i("tab", "上報數據完成################");*/
} else {
UUPoint.saveWriteToIO(UUPointService.this);// 將寫map中的數據持久化到IO
}
} catch (Exception e) {
UUPoint.saveWriteToIO(UUPointService.this);// 將寫map中的數據持久化到IO
}
} else {
UUPoint.saveWriteToIO(UUPointService.this);// 將寫map中的數據持久化到IO
}
}
@Override
public void onError(VolleyError errorResponse) {
MLog.i("tab", "保存到本地文件");
UUPoint.saveWriteToIO(UUPointService.this);
}
@Override
public void networkFinish() {
}
});
}
}
}
// 上傳文件
else if (intent != null && intent.getStringExtra(UUPoint.LOADTYPE) != null && intent.getStringExtra(UUPoint.LOADTYPE).trim().equals(UUPoint.LOADFILE)) {
File file = new File(Config.CountFile);
List<File> fileList = Arrays.asList(file.listFiles());
if (fileList != null && fileList.size() > 0) {
//按文件名稱排序
Collections.sort(fileList, new Comparator<File>() {
@Override
public int compare(File lhs, File rhs) {
return rhs.getName().compareTo(lhs.getName());
}
});
// 上傳文件
for (final File files : fileList) {
// 先解密,在使用票據加密
FileEncrypter.decrypt(files, UUPoint.secretKey);// 解密
if (Config.isNetworkConnected(UUPointService.this)) {
NetworkTask networkTask = new NetworkTask(CmdCodeDef.CmdCode.ReportLogFile_VALUE);
networkTask.setUploadDataFile(true);// 上傳大點數據文件
networkTask.setBusiData(UUPointUtils.getBytesFromFile(files));
NetworkUtils.executeNetwork(networkTask, new HttpResponse.NetWorkResponse<UUResponseData>() {
@Override
public void onSuccessResponse(UUResponseData responseData) {
if (responseData.getRet() == 0) {
try {
SystemInterface.ReportLogInfoResponse response = SystemInterface.ReportLogInfoResponse.parseFrom(responseData.getBusiData());
if (response.getRet() == 0) {
// 上傳成功, 刪除加密文件
files.delete();
MLog.i("tab", "上傳文件完成" + files.getName() + "######################");
} else {
FileEncrypter.encrypt(files, UUPoint.secretKey);// 上傳失敗, 重新加密文件
}
} catch (Exception e) {
e.printStackTrace();
FileEncrypter.encrypt(files, UUPoint.secretKey);// 上傳失敗, 重新加密文件
}
} else {
FileEncrypter.encrypt(files, UUPoint.secretKey);// 上傳失敗, 重新加密文件
}
}
@Override
public void onError(VolleyError errorResponse) {
MLog.i("tab", errorResponse.toString());
FileEncrypter.encrypt(files, UUPoint.secretKey);// 上傳失敗, 重新加密文件
}
@Override
public void networkFinish() {
}
});
}
}
}
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
~~~
**總結**: 一般而言直接使用第三方統計服務就已經可以滿足絕大部分的業務需求了,當然了如果數據比較敏感也可以自己實現數據上報統計的功能。
另外對產品研發技術,技巧,實踐方面感興趣的同學可以參考我的:
[android產品研發(一)-->實用開發規范 ](http://blog.csdn.net/qq_23547831/article/details/51534013)
[android產品研發(二)-->啟動頁優化 ](http://blog.csdn.net/qq_23547831/article/details/51541277)
[android產品研發(三)-->基類Activity ](http://blog.csdn.net/qq_23547831/article/details/51546974)
[android產品研發(四)-->減小Apk大小](http://blog.csdn.net/qq_23547831/article/details/51559066)
[android產品研發(五)-->多渠道打包](http://blog.csdn.net/qq_23547831/article/details/51569261)
[Android產品研發(六)–>Apk混淆](http://blog.csdn.net/qq_23547831/article/details/51581491)
[android產品研發(七)-->Apk熱修復](http://blog.csdn.net/qq_23547831/article/details/51587927)
- 前言
- (一)–>實用開發規范
- (二)-->啟動頁優化
- (三)-->基類Activity
- (四)-->減小Apk大小
- (五)-->多渠道打包
- (六)-->Apk混淆
- (七)-->Apk熱修復
- (八)-->App數據統計
- (九)-->App網絡數據解析
- (十)-->盡量不使用靜態變量保存數據
- (十一)-->應用內跳轉Scheme協議
- (十二)-->App長連接實現
- (十三)-->App輪詢操作
- (十四)-->App升級與更新
- (十五)-->內存對象序列化
- (十六)-->開發者選項
- (十七)-->Hybrid開發
- (十八)-->webview問題集錦
- (十九)-->Android studio中的單元測試
- (二十)-->代碼Review
- (二十一)-->Android中的UI優化
- (二十二)-->Android實用調試技巧
- (二十三)-->Android中保存靜態秘鑰實踐
- (二十四)-->內存泄露場景與檢測
- (二十五)-->MVC/MVVM/MVP簡單理解