Android平台Piwik-SDK源码解析(一)
来源:互联网 发布:网络运营管理岗 面试 编辑:程序博客网 时间:2024/05/22 08:34
本文将对Android平台上的Piwik-SDK进行部分源码解析。
这是Piwik-SDK的github地址:https://github.com/piwik/piwik-sdk-android
我们来看一个追踪页面事件的完整方法:
TrackHelper.track() .screen("/custom_vars") .title("Custom Vars") .variable(1, "first", "var") .variable(2, "second", "long value") .with(getTracker());首先我们调用track()方法获得一个TrackHelper对象:
public static TrackHelper track() { return new TrackHelper(); }该对象拥有screen()、event()等一系列追踪方法,该类还拥有BaseEvent用于上传数据的内部类等,功能繁多。
接下来我们看看screen()方法,它直接new一个Screen对象(Screen同样是TrackHelper的内部类),并在构造方法中初始化入参,super()方法其实是在BaseEvent类中构造一个基础的TrackHelper对象,用于获取一个baseTrackMe对象用作其它用途,在此先不详谈。
Screen(TrackHelper baseBuilder, String path) { super(baseBuilder); mPath = path; }同样的,该类的title()方法也初始化了入参:
public Screen title(String title) { mTitle = title; return this; }然后我们看看它究竟对这些参数做了什么操作:
public TrackMe build() { if (mPath == null) return null; final TrackMe trackMe = new TrackMe(getBaseTrackMe()) .set(QueryParams.URL_PATH, mPath) .set(QueryParams.ACTION_NAME, mTitle); if (mCustomVariables.size() > 0) { //noinspection deprecation trackMe.set(QueryParams.SCREEN_SCOPE_CUSTOM_VARIABLES, mCustomVariables.toString()); } for (Map.Entry<Integer, String> entry : mCustomDimensions.entrySet()) { CustomDimension.setDimension(trackMe, entry.getKey(), entry.getValue()); } return trackMe; }
在Screen类的build()方法里,我们看到他们被保存到了一个TrackMe对象的HashMap中,同样地,若传入了非空的自定义变量对象mCustomVariables,也一并保存。build方法返回了一个TrackMe对象,那这个方法什么时候被调用呢?没错,就是在最后调用的with()方法里:
public void with(@NonNull Tracker tracker) { TrackMe trackMe = build(); if (trackMe != null) tracker.track(trackMe); }每次调用该方法,参数都会被保存在一个TrackMe对象里,然后理所当然就是进行数据的上传了,我们来看它的track()方法:
public Tracker track(TrackMe trackMe) { boolean newSession; synchronized (mSessionLock) { newSession = tryNewSession(); if (newSession) mSessionStartLatch = new CountDownLatch(1); } if (newSession) { injectInitialParams(trackMe); } else { try { // Another thread might be creating a sessions first transmission. mSessionStartLatch.await(getDispatchTimeout(), TimeUnit.MILLISECONDS); } catch (InterruptedException e) { Timber.tag(TAG).e(e, null); } } injectBaseParams(trackMe); mLastEvent = trackMe; if (!mOptOut) { mDispatcher.submit(trackMe); Timber.tag(LOGGER_TAG).d("Event added to the queue: %s", trackMe); } else Timber.tag(LOGGER_TAG).d("Event omitted due to opt out: %s", trackMe); // we did a first transmission, let the other through. if (newSession) mSessionStartLatch.countDown(); return this; }我们看到它有一个同步方法,判断是否是新的追踪对话然后再进行一些配置操作,在此不详谈。最重要的是这段代码:
if (!mOptOut) { mDispatcher.submit(trackMe); Timber.tag(LOGGER_TAG).d("Event added to the queue: %s", trackMe); } else Timber.tag(LOGGER_TAG).d("Event omitted due to opt out: %s", trackMe);
mOptOut是一个表示禁用的标志,在未被禁用的情况下,mDispatcher调用submit()方法开始上传数据:
public void submit(TrackMe trackMe) { mEventCache.add(new Event(trackMe.toMap())); if (mDispatchInterval != -1) launch(); }我们看到它先把trackMe缓存起来,然后调用launch()方法:
private boolean launch() { synchronized (mThreadControl) { if (!mRunning) { mRunning = true; Thread thread = new Thread(mLoop); thread.setPriority(Thread.MIN_PRIORITY); thread.start(); return true; } } return false; }已经很接近了,它使用了一个同步代码块,启动了线程mLoop进行处理,那这个线程做了什么?还是在Dispatcher这个类里:
private Runnable mLoop = new Runnable() { @Override public void run() { while (mRunning) { try { // Either we wait the interval or forceDispatch() granted us one free pass mSleepToken.tryAcquire(mDispatchInterval, TimeUnit.MILLISECONDS); } catch (InterruptedException e) {Timber.tag(LOGGER_TAG).e(e); } if (mEventCache.updateState(isConnected())) { int count = 0; List<Event> drainedEvents = new ArrayList<>(); mEventCache.drainTo(drainedEvents); Timber.tag(LOGGER_TAG).d("Drained %s events.", drainedEvents.size()); for (Packet packet : mPacketFactory.buildPackets(drainedEvents)) { boolean success = false; try { success = dispatch(packet); } catch (IOException e) { // While rapidly dispatching, it's possible that we are connected, but can't resolve hostnames yet // java.net.UnknownHostException: Unable to resolve host "...": No address associated with hostname Timber.tag(LOGGER_TAG).d(e); } if (success) { count += packet.getEventCount(); } else { Timber.tag(LOGGER_TAG).d("Unsuccesful assuming OFFLINE, requeuing events."); mEventCache.updateState(false); mEventCache.requeue(drainedEvents.subList(count, drainedEvents.size())); break; } } Timber.tag(LOGGER_TAG).d("Dispatched %d events.", count); } synchronized (mThreadControl) { // We may be done or this was a forced dispatch if (mEventCache.isEmpty() || mDispatchInterval < 0) { mRunning = false; break; } } } } };这就是整个追踪的流程:初始化、保存数据、上传数据,其中有许多操作我还没有深究,有兴趣的朋友可以交流讨论。
阅读全文
0 0
- Android平台Piwik-SDK源码解析(一)
- android sdk 源码解析
- android sdk 源码解析
- ANDROID SDK 源码解析
- Android SDK 源码解析项目
- android广告平台SDK研发日志(一)
- android drawable源码解析(一)
- Android AsyncTask 源码解析(一)
- Android中Handler源码解析(一)
- Android 源码解析AsyncTask(一)
- Android View 源码解析(一)
- Piwik-SDK浅谈
- newrelic的android sdk实现原理解析(一)
- piwik源码安装
- Android源码:事件分发源码解析(一)
- tango+unity的sdk中experimental三维重建项目源码解析(一)
- Android源码解析之(一)-->Android项目构建过程
- android源码解析之(一)-->android项目构建过程
- python爬虫系列(一)百度首页爬取
- 不安装Oracle使用PlSqlDeveloper
- Go 练习
- vs2015下,使用人脸检测算法对FDDB数据集进行测评
- 万树IT:零基础也能学习安卓开发
- Android平台Piwik-SDK源码解析(一)
- 使用Jackson进行序列化和反序列化
- javascript系列之数组去重(传统和es6)
- 现在学java,能拿到多少工资?
- dubbo的简单学习及原理介绍
- Callable、Future和FutureTask原理解析
- 1.1java基础部分一:java的基本数据类型
- 查询Oracle最近插入语句
- Python3文件操作