这几天项目需要,简单研究了一下countly,说实话完全满足项目需要,比umeng这类产品干净多了。

Countly Mobile Analytics

下面就讲一下android 集成的过程,以及 服务器端报表部分的使用。

1、android 集成。

下载完后,一个工程4个文件,很整洁,赞一个。

这个工程,运行之前把libary去掉勾选,默认这个工程被设置成一个库了。

然后,直接打开CounlyActivity.java这个文件,

Countly.sharedInstance().init(this,你的服务器地址,你的app_key);

上面的你的服务器地址和你的app_key都是先要安装好服务端的程序才能设置的。

下面讲一下服务器端程序的安装和使用。

1、下载完程序后,直接进入bin目录执行sh counly.install.sh ,等5分钟自动全部安装完毕,这方便多了,发现采用node.js代码写的,效率就有些打折扣了。


对了,我的系统是unbuntu  server.

2、它会给你自动装上nginx ,如果你服务器上已经安装apache了,会提示你80端口被占,这个需要你去设置以下nginx.conf里的listen port,随便改个端口就行了

3、服务器网站访问成功后,就在 “管理”-“应用”里添加一个新的应用:

应用密钥就是在android里需要的app_key。

这样子就连通了。

下面简单讲一下会出现的问题:

10-12 15:00:52.570: E/SQLiteDatabase(15701): close() was never explicitly called on database '/data/data/ly.count.android.api/databases/countly'

如果你发现出现这个异常,基本上就是CountlyDB的全部操作没有执行db.close()方法,然后在activiy的stop方法也没有关闭sqlite 数据库导致的,下面就是我简单修改的CountlyDB.java

  1. package ly.count.android.api;
  2.  
  3. import java.io.InputStream;
  4. import java.io.UnsupportedEncodingException;
  5. import java.net.URI;
  6. import java.util.ArrayList;
  7. import java.util.HashMap;
  8. import java.util.Iterator;
  9. import java.util.Locale;
  10. import java.util.Map;
  11. import java.util.Timer;
  12. import java.util.TimerTask;
  13.  
  14. import org.OpenUDID.OpenUDID_manager;
  15. import org.apache.http.HttpResponse;
  16. import org.apache.http.client.methods.HttpGet;
  17. import org.apache.http.impl.client.DefaultHttpClient;
  18. import org.json.JSONArray;
  19. import org.json.JSONException;
  20. import org.json.JSONObject;
  21.  
  22. import android.content.Context;
  23. import android.content.pm.PackageManager.NameNotFoundException;
  24. import android.database.Cursor;
  25. import android.database.sqlite.SQLiteDatabase;
  26. import android.database.sqlite.SQLiteOpenHelper;
  27. import android.telephony.TelephonyManager;
  28. import android.util.DisplayMetrics;
  29. import android.util.Log;
  30. import android.view.Display;
  31. import android.view.WindowManager;
  32.  
  33. public class Countly {
  34. private static Countly sharedInstance_;
  35. private Timer timer_;
  36. private ConnectionQueue queue_;
  37. private EventQueue eventQueue_;
  38. private boolean isVisible_;
  39. private double unsentSessionLength_;
  40. private double lastTime_;
  41. private int activityCount_;
  42. private CountlyDB countlyDB_;
  43.  
  44. static public Countly sharedInstance() {
  45. if (sharedInstance_ == null)
  46. sharedInstance_ = new Countly();
  47.  
  48. return sharedInstance_;
  49. }
  50.  
  51. private Countly() {
  52. queue_ = new ConnectionQueue();
  53. timer_ = new Timer();
  54. timer_.schedule(new TimerTask() {
  55. @Override
  56. public void run() {
  57. onTimer();
  58. }
  59. }, 60 * 1000, 60 * 1000);
  60.  
  61. isVisible_ = false;
  62. unsentSessionLength_ = 0;
  63. activityCount_ = 0;
  64. }
  65.  
  66. public void init(Context context, String serverURL, String appKey) {
  67. OpenUDID_manager.sync(context);
  68. countlyDB_ = new CountlyDB(context);
  69.  
  70. queue_.setContext(context);
  71. queue_.setServerURL(serverURL);
  72. queue_.setAppKey(appKey);
  73. queue_.setCountlyDB(countlyDB_);
  74.  
  75. eventQueue_ = new EventQueue(countlyDB_);
  76. }
  77.  
  78. public void onStart() {
  79. activityCount_++;
  80. if (activityCount_ == 1)
  81. onStartHelper();
  82. }
  83.  
  84. public void onStop() {
  85. activityCount_--;
  86. if (activityCount_ == 0)
  87. onStopHelper();
  88.  
  89. if(countlyDB_!=null){
  90. countlyDB_.close();
  91. }
  92. }
  93.  
  94. public void onStartHelper() {
  95. lastTime_ = System.currentTimeMillis() / 1000.0;
  96.  
  97. queue_.beginSession();
  98.  
  99. isVisible_ = true;
  100. }
  101.  
  102. public void onStopHelper() {
  103. if (eventQueue_.size() > 0)
  104. queue_.recordEvents(eventQueue_.events());
  105.  
  106. double currTime = System.currentTimeMillis() / 1000.0;
  107. unsentSessionLength_ += currTime - lastTime_;
  108.  
  109. int duration = (int) unsentSessionLength_;
  110. queue_.endSession(duration);
  111. unsentSessionLength_ -= duration;
  112.  
  113. isVisible_ = false;
  114. }
  115.  
  116. public void recordEvent(String key, int count) {
  117. eventQueue_.recordEvent(key, count);
  118.  
  119. if (eventQueue_.size() >= 10)
  120. queue_.recordEvents(eventQueue_.events());
  121. }
  122.  
  123. public void recordEvent(String key, int count, double sum) {
  124. eventQueue_.recordEvent(key, count, sum);
  125.  
  126. if (eventQueue_.size() >= 10)
  127. queue_.recordEvents(eventQueue_.events());
  128. }
  129.  
  130. public void recordEvent(String key, Map<String, String> segmentation, int count) {
  131. eventQueue_.recordEvent(key, segmentation, count);
  132.  
  133. if (eventQueue_.size() >= 10)
  134. queue_.recordEvents(eventQueue_.events());
  135. }
  136.  
  137. public void recordEvent(String key, Map<String, String> segmentation, int count, double sum) {
  138. eventQueue_.recordEvent(key, segmentation, count, sum);
  139.  
  140. if (eventQueue_.size() >= 10)
  141. queue_.recordEvents(eventQueue_.events());
  142. }
  143.  
  144. private void onTimer() {
  145. if (isVisible_ == false)
  146. return;
  147.  
  148. double currTime = System.currentTimeMillis() / 1000.0;
  149. unsentSessionLength_ += currTime - lastTime_;
  150. lastTime_ = currTime;
  151.  
  152. int duration = (int) unsentSessionLength_;
  153. queue_.updateSession(duration);
  154. unsentSessionLength_ -= duration;
  155.  
  156. if (eventQueue_.size() > 0)
  157. queue_.recordEvents(eventQueue_.events());
  158. }
  159. }
  160.  
  161. class ConnectionQueue {
  162. private CountlyDB queue_;
  163. private Thread thread_ = null;
  164. private String appKey_;
  165. private Context context_;
  166. private String serverURL_;
  167.  
  168. public void setAppKey(String appKey) {
  169. appKey_ = appKey;
  170. }
  171.  
  172. public void setContext(Context context) {
  173. context_ = context;
  174. }
  175.  
  176. public void setServerURL(String serverURL) {
  177. serverURL_ = serverURL;
  178. }
  179.  
  180. public void setCountlyDB(CountlyDB countlyDB) {
  181. queue_ = countlyDB;
  182. }
  183.  
  184. public void beginSession() {
  185. String data;
  186. data = "app_key=" + appKey_;
  187. data += "&" + "device_id=" + DeviceInfo.getUDID();
  188. data += "&" + "timestamp=" + (long) (System.currentTimeMillis() / 1000.0);
  189. data += "&" + "sdk_version=" + "2.0";
  190. data += "&" + "begin_session=" + "1";
  191. data += "&" + "metrics=" + DeviceInfo.getMetrics(context_);
  192.  
  193. queue_.offer(data);
  194.  
  195. tick();
  196. }
  197.  
  198. public void updateSession(int duration) {
  199. String data;
  200. data = "app_key=" + appKey_;
  201. data += "&" + "device_id=" + DeviceInfo.getUDID();
  202. data += "&" + "timestamp=" + (long) (System.currentTimeMillis() / 1000.0);
  203. data += "&" + "session_duration=" + duration;
  204.  
  205. queue_.offer(data);
  206.  
  207. tick();
  208. }
  209.  
  210. public void endSession(int duration) {
  211. String data;
  212. data = "app_key=" + appKey_;
  213. data += "&" + "device_id=" + DeviceInfo.getUDID();
  214. data += "&" + "timestamp=" + (long) (System.currentTimeMillis() / 1000.0);
  215. data += "&" + "end_session=" + "1";
  216. data += "&" + "session_duration=" + duration;
  217.  
  218. queue_.offer(data);
  219.  
  220. tick();
  221. }
  222.  
  223. public void recordEvents(String events) {
  224. String data;
  225. data = "app_key=" + appKey_;
  226. data += "&" + "device_id=" + DeviceInfo.getUDID();
  227. data += "&" + "timestamp=" + (long) (System.currentTimeMillis() / 1000.0);
  228. data += "&" + "events=" + events;
  229.  
  230. queue_.offer(data);
  231.  
  232. tick();
  233. }
  234.  
  235. private void tick() {
  236. if (thread_ != null && thread_.isAlive())
  237. return;
  238.  
  239. if (queue_.isEmpty())
  240. return;
  241.  
  242. thread_ = new Thread() {
  243. @Override
  244. public void run() {
  245. while (true) {
  246. String data = queue_.peek();
  247.  
  248. if (data == null)
  249. break;
  250.  
  251. int index = data.indexOf("REPLACE_UDID");
  252. if (index != -1) {
  253. if (OpenUDID_manager.isInitialized() == false)
  254. break;
  255. data = data.replaceFirst("REPLACE_UDID", OpenUDID_manager.getOpenUDID());
  256. }
  257.  
  258. try {
  259. DefaultHttpClient httpClient = new DefaultHttpClient();
  260. HttpGet method = new HttpGet(new URI(serverURL_ + "/i?" + data));
  261. HttpResponse response = httpClient.execute(method);
  262. InputStream input = response.getEntity().getContent();
  263. while (input.read() != -1)
  264. ;
  265. httpClient.getConnectionManager().shutdown();
  266.  
  267. Log.d("Countly", "ok ->" + data);
  268.  
  269. queue_.poll();
  270. } catch (Exception e) {
  271. Log.d("Countly", e.toString());
  272. Log.d("Countly", "error ->" + data);
  273. break;
  274. }
  275. }
  276. }
  277. };
  278.  
  279. thread_.start();
  280. }
  281. }
  282.  
  283. class DeviceInfo {
  284. public static String getUDID() {
  285. return OpenUDID_manager.isInitialized() == false ? "REPLACE_UDID" : OpenUDID_manager.getOpenUDID();
  286. }
  287.  
  288. public static String getOS() {
  289. return "Android";
  290. }
  291.  
  292. public static String getOSVersion() {
  293. return android.os.Build.VERSION.RELEASE;
  294. }
  295.  
  296. public static String getDevice() {
  297. return android.os.Build.MODEL;
  298. }
  299.  
  300. public static String getResolution(Context context) {
  301. WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
  302.  
  303. Display display = wm.getDefaultDisplay();
  304.  
  305. DisplayMetrics metrics = new DisplayMetrics();
  306. display.getMetrics(metrics);
  307.  
  308. return metrics.widthPixels + "x" + metrics.heightPixels;
  309. }
  310.  
  311. public static String getCarrier(Context context) {
  312. TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
  313. return manager.getNetworkOperatorName();
  314. }
  315.  
  316. public static String getLocale() {
  317. Locale locale = Locale.getDefault();
  318. return locale.getLanguage() + "_" + locale.getCountry();
  319. }
  320.  
  321. public static String appVersion(Context context) {
  322. String result = "1.0";
  323. try {
  324. result = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName;
  325. } catch (NameNotFoundException e) {
  326. }
  327.  
  328. return result;
  329. }
  330.  
  331. public static String getMetrics(Context context) {
  332. String result = "";
  333. JSONObject json = new JSONObject();
  334.  
  335. try {
  336. json.put("_device", getDevice());
  337. json.put("_os", getOS());
  338. json.put("_os_version", getOSVersion());
  339. json.put("_carrier", getCarrier(context));
  340. json.put("_resolution", getResolution(context));
  341. json.put("_locale", getLocale());
  342. json.put("_app_version", appVersion(context));
  343. } catch (JSONException e) {
  344. e.printStackTrace();
  345. }
  346.  
  347. result = json.toString();
  348.  
  349. try {
  350. result = java.net.URLEncoder.encode(result, "UTF-8");
  351. } catch (UnsupportedEncodingException e) {
  352.  
  353. }
  354.  
  355. return result;
  356. }
  357. }
  358.  
  359. class Event {
  360. public String key = null;
  361. public Map<String, String> segmentation = null;
  362. public int count = 0;
  363. public double sum = 0;
  364. public int timestamp = 0;
  365. }
  366.  
  367. class EventQueue {
  368. private ArrayList<Event> events_;
  369. private CountlyDB countlyDB_;
  370.  
  371. public EventQueue(CountlyDB countlyDB) {
  372. countlyDB_ = countlyDB;
  373. events_ = countlyDB_.getEvents();
  374. }
  375.  
  376. public int size() {
  377. synchronized (this) {
  378. return events_.size();
  379. }
  380. }
  381.  
  382. public String events() {
  383. String result = "";
  384.  
  385. synchronized (this) {
  386. JSONArray eventArray = new JSONArray();
  387.  
  388. for (int i = 0; i < events_.size(); ++i) {
  389. JSONObject json = new JSONObject();
  390. Event currEvent = events_.get(i);
  391.  
  392. try {
  393. json.put("key", currEvent.key);
  394. json.put("count", currEvent.count);
  395. json.put("sum", currEvent.sum);
  396. json.put("timestamp", currEvent.timestamp);
  397.  
  398. if (currEvent.segmentation != null) {
  399. json.put("segmentation", new JSONObject(currEvent.segmentation));
  400. }
  401. } catch (JSONException e) {
  402. e.printStackTrace();
  403. }
  404.  
  405. eventArray.put(json);
  406. }
  407.  
  408. result = eventArray.toString();
  409.  
  410. events_.clear();
  411. countlyDB_.clearEvents();
  412. }
  413.  
  414. try {
  415. result = java.net.URLEncoder.encode(result, "UTF-8");
  416. } catch (UnsupportedEncodingException e) {
  417.  
  418. }
  419.  
  420. return result;
  421. }
  422.  
  423. public void recordEvent(String key, int count) {
  424. synchronized (this) {
  425. for (int i = 0; i < events_.size(); ++i) {
  426. Event event = events_.get(i);
  427.  
  428. if (event.key.equals(key)) {
  429. event.count += count;
  430. event.timestamp = Math.round((event.timestamp + (System.currentTimeMillis() / 1000)) / 2);
  431. countlyDB_.saveEvents(events_);
  432. return;
  433. }
  434. }
  435.  
  436. Event event = new Event();
  437. event.key = key;
  438. event.count = count;
  439. event.timestamp = Math.round(System.currentTimeMillis() / 1000);
  440. events_.add(event);
  441.  
  442. countlyDB_.saveEvents(events_);
  443. }
  444. }
  445.  
  446. public void recordEvent(String key, int count, double sum) {
  447. synchronized (this) {
  448. for (int i = 0; i < events_.size(); ++i) {
  449. Event event = events_.get(i);
  450.  
  451. if (event.key.equals(key)) {
  452. event.count += count;
  453. event.sum += sum;
  454. event.timestamp = Math.round((event.timestamp + (System.currentTimeMillis() / 1000)) / 2);
  455. countlyDB_.saveEvents(events_);
  456. return;
  457. }
  458. }
  459.  
  460. Event event = new Event();
  461. event.key = key;
  462. event.count = count;
  463. event.sum = sum;
  464. event.timestamp = Math.round(System.currentTimeMillis() / 1000);
  465. events_.add(event);
  466.  
  467. countlyDB_.saveEvents(events_);
  468. }
  469. }
  470.  
  471. public void recordEvent(String key, Map<String, String> segmentation, int count) {
  472. synchronized (this) {
  473. for (int i = 0; i < events_.size(); ++i) {
  474. Event event = events_.get(i);
  475.  
  476. if (event.key.equals(key) && event.segmentation != null && event.segmentation.equals(segmentation)) {
  477. event.count += count;
  478. event.timestamp = Math.round((event.timestamp + (System.currentTimeMillis() / 1000)) / 2);
  479. countlyDB_.saveEvents(events_);
  480. return;
  481. }
  482. }
  483.  
  484. Event event = new Event();
  485. event.key = key;
  486. event.segmentation = segmentation;
  487. event.count = count;
  488. event.timestamp = Math.round(System.currentTimeMillis() / 1000);
  489. events_.add(event);
  490.  
  491. countlyDB_.saveEvents(events_);
  492. }
  493. }
  494.  
  495. public void recordEvent(String key, Map<String, String> segmentation, int count, double sum) {
  496. synchronized (this) {
  497. for (int i = 0; i < events_.size(); ++i) {
  498. Event event = events_.get(i);
  499.  
  500. if (event.key.equals(key) && event.segmentation != null && event.segmentation.equals(segmentation)) {
  501. event.count += count;
  502. event.sum += sum;
  503. event.timestamp = Math.round((event.timestamp + (System.currentTimeMillis() / 1000)) / 2);
  504. countlyDB_.saveEvents(events_);
  505. return;
  506. }
  507. }
  508.  
  509. Event event = new Event();
  510. event.key = key;
  511. event.segmentation = segmentation;
  512. event.count = count;
  513. event.sum = sum;
  514. event.timestamp = Math.round(System.currentTimeMillis() / 1000);
  515. events_.add(event);
  516.  
  517. countlyDB_.saveEvents(events_);
  518. }
  519. }
  520. }
  521.  
  522. class CountlyDB extends SQLiteOpenHelper {
  523.  
  524. private static final int DATABASE_VERSION = 1;
  525. private static final String DATABASE_NAME = "countly";
  526. private static final String CONNECTIONS_TABLE_NAME = "CONNECTIONS";
  527. private static final String EVENTS_TABLE_NAME = "EVENTS";
  528. private static final String CONNECTIONS_TABLE_CREATE = "CREATE TABLE " + CONNECTIONS_TABLE_NAME + " (ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, CONNECTION TEXT NOT NULL);";
  529. private static final String EVENTS_TABLE_CREATE = "CREATE TABLE " + EVENTS_TABLE_NAME + " (ID INTEGER UNIQUE NOT NULL, EVENT TEXT NOT NULL);";
  530.  
  531. CountlyDB(Context context) {
  532. super(context, DATABASE_NAME, null, DATABASE_VERSION);
  533. }
  534.  
  535. @Override
  536. public void onCreate(SQLiteDatabase db) {
  537. db.execSQL(CONNECTIONS_TABLE_CREATE);
  538. db.execSQL(EVENTS_TABLE_CREATE);
  539. }
  540.  
  541. @Override
  542. public void onUpgrade(SQLiteDatabase db, int arg1, int arg2) {
  543.  
  544. }
  545.  
  546. public String peek() {
  547. synchronized (this) {
  548. SQLiteDatabase db = this.getReadableDatabase();
  549.  
  550. Cursor cursor = db.query(CONNECTIONS_TABLE_NAME, null, null, null, null, null, "ID DESC", "1");
  551.  
  552. String connection = null;
  553.  
  554. if (cursor != null && cursor.getCount() > 0) {
  555. cursor.moveToFirst();
  556. connection = cursor.getString(1);
  557. Log.d("Countly", "Fetched: " + connection);
  558. }
  559.  
  560. db.close();
  561. return connection;
  562. }
  563. }
  564.  
  565. public String poll() {
  566. synchronized (this) {
  567. SQLiteDatabase db = this.getReadableDatabase();
  568.  
  569. Cursor cursor = db.query(CONNECTIONS_TABLE_NAME, null, null, null, null, null, "ID DESC", "1");
  570.  
  571. String connection = null;
  572.  
  573. if (cursor != null && cursor.getCount() > 0) {
  574. cursor.moveToFirst();
  575. connection = cursor.getString(1);
  576. int rawId = Integer.parseInt(cursor.getString(0));
  577.  
  578. SQLiteDatabase writeDb = this.getWritableDatabase();
  579. writeDb.execSQL("DELETE FROM " + CONNECTIONS_TABLE_NAME + " WHERE ID = " + rawId + ";");
  580.  
  581. Log.d("Countly", "Fetched and deleted: " + connection);
  582. }
  583. db.close();
  584. return connection;
  585. }
  586. }
  587.  
  588. public void offer(String data) {
  589. SQLiteDatabase db = this.getWritableDatabase();
  590.  
  591. db.execSQL("INSERT INTO " + CONNECTIONS_TABLE_NAME + "(CONNECTION) VALUES('" + data + "');");
  592.  
  593. Log.d("Countly", "Insert into " + CONNECTIONS_TABLE_NAME + ": " + data);
  594. db.close();
  595. }
  596.  
  597. public boolean isEmpty() {
  598. SQLiteDatabase db = this.getReadableDatabase();
  599. Cursor cursor = db.query(CONNECTIONS_TABLE_NAME, null, null, null, null, null, "ID DESC", "1");
  600.  
  601. boolean rtn= !(cursor != null && cursor.getCount() > 0);
  602. db.close();
  603. return rtn;
  604. }
  605.  
  606. // Event related functions
  607.  
  608. public ArrayList<Event> getEvents() {
  609. SQLiteDatabase db = this.getReadableDatabase();
  610.  
  611. Cursor cursor = db.query(EVENTS_TABLE_NAME, null, null, null, null, null, "ID = 1", "1");
  612. ArrayList<Event> eventsArray = new ArrayList<Event>();
  613.  
  614. if (cursor != null && cursor.getCount() > 0) {
  615. cursor.moveToFirst();
  616. String events = cursor.getString(1);
  617.  
  618. JSONObject json = new JSONObject();
  619.  
  620. try {
  621. json = new JSONObject(events);
  622. } catch (JSONException e) {
  623. e.printStackTrace();
  624. }
  625.  
  626. JSONArray jArray = json.optJSONArray("events");
  627.  
  628. if (jArray != null) {
  629. for (int i = 0; i < jArray.length(); i++) {
  630. try {
  631. eventsArray.add(jsonToEvent(new JSONObject(jArray.get(i).toString())));
  632. } catch (JSONException e) {
  633. e.printStackTrace();
  634. }
  635. }
  636. }
  637. }
  638. db.close();
  639.  
  640. return eventsArray;
  641. }
  642.  
  643. public void saveEvents(ArrayList<Event> events) {
  644. JSONArray eventArray = new JSONArray();
  645. JSONObject json = new JSONObject();
  646.  
  647. for (int i = 0; i < events.size(); ++i) {
  648. eventArray.put(eventToJSON(events.get(i)));
  649. }
  650.  
  651. try {
  652. json.put("events", eventArray);
  653. } catch (JSONException e) {
  654. e.printStackTrace();
  655. }
  656.  
  657. SQLiteDatabase db = this.getWritableDatabase();
  658.  
  659. db.execSQL("INSERT OR REPLACE INTO " + EVENTS_TABLE_NAME + "(ID, EVENT) VALUES(1, '" + json.toString() + "');");
  660. db.close();
  661. }
  662.  
  663. public void clearEvents() {
  664. SQLiteDatabase writeDb = this.getWritableDatabase();
  665. writeDb.execSQL("DELETE FROM " + EVENTS_TABLE_NAME + ";");
  666. writeDb.close();
  667. }
  668.  
  669. private JSONObject eventToJSON(Event event) {
  670. JSONObject json = new JSONObject();
  671.  
  672. try {
  673. json.put("key", event.key);
  674. json.put("count", event.count);
  675. json.put("sum", event.sum);
  676. json.put("timestamp", event.timestamp);
  677.  
  678. if (event.segmentation != null) {
  679. json.put("segmentation", new JSONObject(event.segmentation));
  680. }
  681. } catch (JSONException e) {
  682. e.printStackTrace();
  683. }
  684.  
  685. return json;
  686. }
  687.  
  688. private Event jsonToEvent(JSONObject json) {
  689. Event event = new Event();
  690.  
  691. try {
  692. event.key = json.get("key").toString();
  693. event.count = Integer.valueOf(json.get("count").toString());
  694. event.sum = Double.valueOf(json.get("sum").toString());
  695. event.timestamp = Integer.valueOf(json.get("timestamp").toString());
  696.  
  697. HashMap<String, String> segmentation = new HashMap<String, String>();
  698. @SuppressWarnings("unchecked")
  699. Iterator<String> nameItr = ((JSONObject) json.get("segmentation")).keys();
  700.  
  701. while (nameItr.hasNext()) {
  702. String key = nameItr.next();
  703. segmentation.put(key, ((JSONObject) json.get("segmentation")).getString(key));
  704. }
  705.  
  706. event.segmentation = segmentation;
  707. } catch (JSONException e) {
  708. e.printStackTrace();
  709. }
  710.  
  711. return event;
  712. }
  713. }

最后讲一下,自定义事件的使用。

  1. Countly.sharedInstance().recordEvent("open acivity", count++);
  2.  
  3. Map<String, String> music = new HashMap<String, String>();
  4. music.put("type", "popular");
  5. music.put("artist", "JJLin");
  6. music.put("User_status", "registered");
  7. Countly.sharedInstance().recordEvent( "music",music,count++);

你看Countly提供了好几种方式:

第一种方式,就是一个tag和一个计数,足够我们使用了。

对于第三种,我觉得有更高需要采用的到,举个例子:

http://dev.umeng.com/analytics/android/%E8%87%AA%E5%AE%9A%E4%B9%89%E4%BA%8B%E4%BB%B6%E6%A1%88%E4%BE%8B

附上网站自定义事件的报表:

如果大家有啥问题可以找我讨论。

Countly在andoid和vps集成使用,开源的统计分析sdk的更多相关文章

  1. [转]Infobright是一个与MySQL集成的开源数据仓库

    [文章作者:张宴 本文版本:v1.1 最后修改:2010.05.18 转载请注明原文链接:http://blog.zyan.cc/infobright/] Infobright是一个与MySQL集成的 ...

  2. 学会这几步,简单集成视频编辑原子能力SDK

    华为视频编辑服务6.2.0版本上线后,我们为大家带来了两大变化:分别是丰富多样的AI能力和灵活选择的集成方式.为让开发者更快上手使用,今天小编带来了视频编辑原子能力SDK的具体集成方法.快来试试吧! ...

  3. 微信小程序集成腾讯云 IM SDK

    微信小程序集成腾讯云 IM SDK 1.背景 因业务功能需求需要接入IM(即时聊天)功能,一开始想到的是使用 WebSocket 来实现这个功能,然天意捉弄(哈哈)服务器版本太低不支持 wx 协议(也 ...

  4. 设定十分钟android在状态栏上集成的开源project推荐

    1.前言 于android kitkat 有一个新功能可以设置背景的手机状态栏,让手机风的整个界面格是一致的,它看起来非常酷,在今年的google i/o向上android l这样的风格.来如今看我们 ...

  5. iOS编译集成linux开源c库的一些记录

    最近一个iOS项目需要使用一些Linux下面的开源c库,说是Linux的其实是跨平台的,各种Unix系统都有支持.理论上iOS来自MacOS,而MacOS其实是一种兼容的Unix系统,所以这些库应该也 ...

  6. 云原生强大且灵活的持续集成CI开源框架Tekton实战-上

    @ 目录 概述 定义 常见CICD工具 使用好处 组件 基本概念 安装 前提条件 安装Tekton Pipelines 创建并运行任务 安装Dashboard 安装Cli Pipelines示例演示 ...

  7. MyBridgeWebViewDemo【集成JsBridge开源库的的封装的webview】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 使用的是第三方库lzyzsd/JsBridge,但是不同的是,将自己封装的MyBridgeWebView通过继承BridgeWebV ...

  8. 集成支付宝钱包支付iOS SDK的方法与经验

    流程 摘自第一个文档<支付宝钱包支付接口开发包2.0标准版.pdf> 图中的“商户客户端”就是我们的iOS客户端需要做的事情: 调用支付宝支付接口 处理支付宝返回的支付结果 在调用支付宝支 ...

  9. 集成支付宝钱包支付ios SDK的方法和经验

    没想到,支付宝的SDK是我目前用过的所有第三方SDK中最难用的一个了. 下载 首先,你要想找到这个SDK,都得费点功夫.现在的SDK改名叫移动支付集成开发包了,下载页面在 这里 的 “请点此下载集成开 ...

随机推荐

  1. YII数据库操作中打印sql

    配置如下: 'components' => array( 'db'=>array( 'enableParamLogging' => true, ), 'log'=>array( ...

  2. 我的JAVA基础学习史1

    又开始学习了..很是兴奋呢~~~~ 本来是想学安卓的,但是安卓的视频课程中,第一阶段是环境,第二阶段是JAVA基础(讲课的这个老师真是在念课本,但是实在没有办法,没找到更好.更完整的资料了). 虽然以 ...

  3. javascript里的post和get有什么区别

    FORM中的get post方法区别Form中的get和post方法,在数据传输过程中分别对应了HTTP协议中的GET和POST方法.二者主要区别如下: 1.Get是用来从服务器上获得数据,而Post ...

  4. 1106. Two Teams(dfs 染色)

    1106 结点染色 当前结点染为黑 朋友染为白  依次染下去 这题是为二分图打基础吧 #include <iostream> #include<cstdio> #include ...

  5. 宏ut_2pow_remainder

    求余数 12%8=4 n%m也能计算出余数,但效率可能比位操作要低一些 /*************************************************************// ...

  6. poj2352

    纪念树状数组初步(……): 这题已经给了y升序,y相同时x升序,(yeah) 所以容易想到O(n^2)的模拟算法: 其实分析一下就是对于当前xi,统计之前有多少个小于等于xi(因为已经保证了没有相同坐 ...

  7. hdu 3367 Pseudoforest

    Pseudoforest Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) To ...

  8. Mysql加密方式

    MySQL数据库的认证密码有两种方式, MySQL 4.1版本之前是MySQL323加密,MySQL 4.1和之后的版本都是MySQLSHA1加密, MySQL数据库中自带Old_Password(s ...

  9. 让memcached和mysql更好的工作

    这次是Fotolog的经验,传说中比Flickr更大的网站,Fotolog在21台服务器上部署了51个memcached实例,总计有254G缓存空间可用,缓存了多达175G的内容,这个数量比很多网站的 ...

  10. 我的WCF之旅(3):在WCF中实现双工通信

    双工(Duplex)模式的消息交换方式体现在消息交换过程中,参与的双方均可以向对方发送消息.基于双工MEP消息交换可以看成是多个基本模式下(比如请求-回复模式和单项模式)消息交换的组合.双工MEP又具 ...