diff --git a/tracker/src/main/java/com/foolchen/lib/tracker/data/TrackerEvent.kt b/tracker/src/main/java/com/foolchen/lib/tracker/data/TrackerEvent.kt index 11f5894..1b605ed 100644 --- a/tracker/src/main/java/com/foolchen/lib/tracker/data/TrackerEvent.kt +++ b/tracker/src/main/java/com/foolchen/lib/tracker/data/TrackerEvent.kt @@ -54,6 +54,9 @@ data class TrackerEvent( o.putAll(buildInObject) o[EVENT] = event o[TIME] = time + Tracker.projectName?.let { o.put("project_name", it) } + o["mode"] = mode() + o["type"] = "track" o[LIB] = buildInLib val properties = HashMap() diff --git a/tracker/src/main/java/com/foolchen/lib/tracker/service/TrackerAPIDef.kt b/tracker/src/main/java/com/foolchen/lib/tracker/service/TrackerAPIDef.kt index 61b237f..eb82058 100644 --- a/tracker/src/main/java/com/foolchen/lib/tracker/service/TrackerAPIDef.kt +++ b/tracker/src/main/java/com/foolchen/lib/tracker/service/TrackerAPIDef.kt @@ -1,11 +1,9 @@ package com.foolchen.lib.tracker.service import io.reactivex.Observable +import okhttp3.RequestBody import retrofit2.Response -import retrofit2.http.Field -import retrofit2.http.FormUrlEncoded -import retrofit2.http.POST -import retrofit2.http.Path +import retrofit2.http.* /** * 上报接口的定义 @@ -18,13 +16,20 @@ interface TrackerAPIDef { /** * 上报数据接口 * - * @param path 上报数据的接口地址 - * @param projectName 要上报数据的项目名称 * @param data 要上报的JSON数据 - * @param mode 上报数据的模式 */ @FormUrlEncoded @POST("{url}") - fun report(@Path("url") path: String, @Field("project") projectName: String, @Field( - "data") data: String, @Field("mode") mode: Int): Observable> + fun report( + @Path("url") path: String, + @Field("data_list") data: String + ): Observable> + + /** + * 上报数据接口 + * + * @param data 要上报的JSON数据 + */ + @POST("{url}") + fun report(@Path("url") path: String, @Body body: RequestBody): Observable> } \ No newline at end of file diff --git a/tracker/src/main/java/com/foolchen/lib/tracker/service/TrackerService.kt b/tracker/src/main/java/com/foolchen/lib/tracker/service/TrackerService.kt index 1b6c053..b9545db 100644 --- a/tracker/src/main/java/com/foolchen/lib/tracker/service/TrackerService.kt +++ b/tracker/src/main/java/com/foolchen/lib/tracker/service/TrackerService.kt @@ -13,7 +13,9 @@ import io.reactivex.Observable import io.reactivex.Observer import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers +import okhttp3.MediaType import okhttp3.OkHttpClient +import okhttp3.RequestBody import org.jetbrains.anko.db.* import retrofit2.Response import retrofit2.Retrofit @@ -47,78 +49,68 @@ object TrackerService { if (Tracker.mode == TrackerMode.RELEASE) { // 如果为release模式,则此处需要考虑同步、批量上传等处理 // 首先将事件添加到事件列表中 - mEvents.add(event) + addEvent(event) // 然后判断事件数量是否达到了上传的阈值 if (mEvents.size >= threshold() || background || foreground) { // 如果达到了阈值,则进行后续操作 val reportEvents = prepareEvents()// 准备要上报的事件 report(reportEvents, - // 在从后台切换到前台时,将反序列化方法当做实参传入,用于将数据库中的事件读取出来 - if (foreground) this@TrackerService::deserializeEvents else null, - // 如果当前要统计的事件为切换到后台,则将序列化方法当做实参传递,用于在上报失败后将数据存储到数据库 - // 否则,将恢复事件方法当做实参传递,在上报失败后,将数据再次添加到候选列表中 - if (background) this@TrackerService::serializeEvents else this@TrackerService::addEvents) + // 在从后台切换到前台时,将反序列化方法当做实参传入,用于将数据库中的事件读取出来 + if (foreground) this@TrackerService::deserializeEvents else null, + // 如果当前要统计的事件为切换到后台,则将序列化方法当做实参传递,用于在上报失败后将数据存储到数据库 + // 否则,将恢复事件方法当做实参传递,在上报失败后,将数据再次添加到候选列表中 + if (background) this@TrackerService::serializeEvents else this@TrackerService::addEvents) } } else if (Tracker.mode == TrackerMode.DEBUG_TRACK) { // 如果为debug&track模式,则直接上传数据,并且不关注失败 - mService.report(Tracker.servicePath!!, Tracker.projectName!!, - prepareReportJson(listOf(event)), - mode()).subscribeOn(Schedulers.io()).observeOn(Schedulers.io()).subscribe( - IgnoreObserver()) + mService.report(Tracker.servicePath!!, + createRequestBody(prepareReportJson(listOf(event)))).subscribeOn( + Schedulers.io()).observeOn( + Schedulers.io()).subscribe( + IgnoreObserver()) } } private fun report(events: List, deserializeFunc: KFunction0>?, - failureFunc: (List) -> Unit) { + failureFunc: (List) -> Unit) { Observable - .create> { - // 如果传入的反序列化方法不为空,则将反序列化的数据传递到下一步 - // 否则,则传递一个空的List - it.onNext(deserializeFunc?.invoke() ?: Collections.emptyList()) - it.onComplete() - } - .map { - // 此处,在反序列化数据不为空的情况下,将反序列化数据添加到要上报的数据中 - (events as MutableList).addAll(it) // 由于已知此处肯定为ArrayList,故直接进行转换 - events - } - .flatMap { - mService.report(Tracker.servicePath!!, Tracker.projectName!!, - prepareReportJson(it), mode()) - } - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.io()) - .subscribe(object : IgnoreObserver() { - override fun onNext(t: Response) { - super.onNext(t) - if (t.code() == 200) { - // 接口请求成功 - // 则此时不做任何处理 - } else { - // 接口请求失败 - // 则此时将上报失败的事件添加回待上报的事件列表中 - failureFunc.invoke(events) - } - } - - override fun onError(e: Throwable) { - super.onError(e) + .create> { + // 如果传入的反序列化方法不为空,则将反序列化的数据传递到下一步 + // 否则,则传递一个空的List + it.onNext(deserializeFunc?.invoke() ?: Collections.emptyList()) + it.onComplete() + } + .map { + // 此处,在反序列化数据不为空的情况下,将反序列化数据添加到要上报的数据中 + (events as MutableList).addAll(it) // 由于已知此处肯定为ArrayList,故直接进行转换 + events + } + .flatMap { + mService.report(Tracker.servicePath!!, + createRequestBody(prepareReportJson(it))) + } + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.io()) + .subscribe(object : IgnoreObserver() { + override fun onNext(t: Response) { + super.onNext(t) + if (t.code() == 200) { + // 接口请求成功 + // 则此时不做任何处理 + } else { // 接口请求失败 // 则此时将上报失败的事件添加回待上报的事件列表中 failureFunc.invoke(events) } - }) - } + } - /** 根据枚举类型来计算上报接口时使用的模式 */ - private fun mode(): Int { - return when (Tracker.mode) { - TrackerMode.DEBUG_ONLY -> 1 - TrackerMode.DEBUG_TRACK -> 2 - else -> { - 3 - } - } + override fun onError(e: Throwable) { + super.onError(e) + // 接口请求失败 + // 则此时将上报失败的事件添加回待上报的事件列表中 + failureFunc.invoke(events) + } + }) } /** 根据当前的上报模式计算触发上报的阈值 */ @@ -151,6 +143,13 @@ object TrackerService { mEvents.sortBy { it.time } } + /** 将一批事件添加到事件列表中,该操作为同步操作 */ + @Synchronized + private fun addEvent(event: TrackerEvent) { + mEvents.add(event) + // 在添加到列表中后,根据时间对所有的时间进行排序 + mEvents.sortBy { it.time } + } /** 准备上传使用的JSON数据 */ private fun prepareReportJson(events: List): String { @@ -166,14 +165,17 @@ object TrackerService { return json } + private fun createRequestBody(s: String) = RequestBody.create(MediaType.parse("text/plain"), + "data_list=$s") + /** 对事件列表进行持久化 */ private fun serializeEvents(events: List) { - Tracker.trackContext.getApplicationContext().let { + Tracker.trackContext?.getApplicationContext()?.let { it.database.use { transaction { events.forEach { insert(EventContract.TABLE_NAME, EventContract.DATA to GSON.toJson(it), - EventContract.TIME to it.time) + EventContract.TIME to it.time) } } } @@ -183,19 +185,19 @@ object TrackerService { /** 对事件列表进行反持久化 */ private fun deserializeEvents(): List { val events = ArrayList() - Tracker.trackContext.getApplicationContext().database.use { + Tracker.trackContext?.getApplicationContext()?.database?.use { // 查找出所有的数据 select(EventContract.TABLE_NAME, EventContract.DATA).orderBy(EventContract.TIME, - SqlOrderDirection.ASC) - .exec { - val deserializeEvents = parseList(object : RowParser { - override fun parseRow(columns: Array): TrackerEvent { - val data = columns[0] as String - return GSON.fromJson(data, TrackerEvent::class.java) - } - }) - events.addAll(deserializeEvents) - } + SqlOrderDirection.ASC) + .exec { + val deserializeEvents = parseList(object : RowParser { + override fun parseRow(columns: Array): TrackerEvent { + val data = columns[0] as String + return GSON.fromJson(data, TrackerEvent::class.java) + } + }) + events.addAll(deserializeEvents) + } // 然后将所有的数据从数据库中删除 delete(EventContract.TABLE_NAME) } @@ -220,9 +222,9 @@ object TrackerService { builder.baseUrl(Tracker.serviceHost!!) builder.client(createOkHttpClient()) mRetrofit = builder - .addConverterFactory(ToStringConverterFactory()) - .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) - .build() + .addConverterFactory(ToStringConverterFactory()) + .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) + .build() } } return mRetrofit!! @@ -230,9 +232,9 @@ object TrackerService { private fun createOkHttpClient(): OkHttpClient { return OkHttpClient.Builder().connectTimeout(Tracker.timeoutDuration, - TimeUnit.MILLISECONDS) - .readTimeout(Tracker.timeoutDuration, TimeUnit.MILLISECONDS) - .writeTimeout(Tracker.timeoutDuration, TimeUnit.MILLISECONDS).build() + TimeUnit.MILLISECONDS) + .readTimeout(Tracker.timeoutDuration, TimeUnit.MILLISECONDS) + .writeTimeout(Tracker.timeoutDuration, TimeUnit.MILLISECONDS).build() } /** [Observer]的实现类,默认实现忽略所有回调。如有需要可覆写对应方法 */ diff --git a/tracker/src/main/java/com/foolchen/lib/tracker/utils/TrackerUtils.kt b/tracker/src/main/java/com/foolchen/lib/tracker/utils/TrackerUtils.kt index 7ee24a4..2340703 100644 --- a/tracker/src/main/java/com/foolchen/lib/tracker/utils/TrackerUtils.kt +++ b/tracker/src/main/java/com/foolchen/lib/tracker/utils/TrackerUtils.kt @@ -93,7 +93,6 @@ internal fun Fragment.getTrackProperties(): Map { return properties } -@Suppress("UNUSED_PARAMETER") internal fun View.getTrackProperties(ev: MotionEvent?): Map { // 首先获取元素本身的属性 val properties = HashMap() @@ -115,6 +114,17 @@ internal fun View.getTrackProperties(ev: MotionEvent?): Map { return properties } +/** 根据枚举类型来计算上报接口时使用的模式 */ +internal fun mode(): Int { + return when (Tracker.mode) { + TrackerMode.DEBUG_ONLY -> 1 + TrackerMode.DEBUG_TRACK -> 2 + else -> { + 3 + } + } +} + /** * 对事件进行统计 * @@ -123,7 +133,7 @@ internal fun View.getTrackProperties(ev: MotionEvent?): Map { * @param foreground 当前事件是否为切换到前台 */ internal fun trackEvent(event: TrackerEvent, background: Boolean = false, - foreground: Boolean = false) { + foreground: Boolean = false) { // 此处尝试对数据进行上报 // 具体的上报策略由TrackerService掌控 TrackerService.report(event, background, foreground)