出行动态数据库相关操作迁移至单例,方便初始化

This commit is contained in:
tongchenfei
2020-07-09 14:40:38 +08:00
parent 54ab418dea
commit cc07e79efa
9 changed files with 232 additions and 175 deletions

View File

@@ -17,6 +17,7 @@ import com.zhidao.mogo.module.event.panel.EventPanelConstants.MODULE_NAME
import com.zhidao.mogo.module.event.panel.EventPanelConstants.PATH_NAME
import com.zhidao.mogo.module.event.panel.fragment.EventPanelFragment
import com.zhidao.mogo.module.event.panel.util.MogoApiManager
import com.zhidao.mogo.module.event.panel.util.TripRecordDataManager
/**
* 事件面板provider
@@ -33,6 +34,7 @@ class EventPanelModuleProvider : IEventPanelProvider {
override fun init(context: Context) {
Logger.d(MODULE_NAME, "模块初始化====")
MogoApiManager.init(context)
TripRecordDataManager.init(context)
}
override fun createFragment(context: Context, data: Bundle?): Fragment? {

View File

@@ -20,7 +20,7 @@ interface TripRecordDao {
@Query(value = "SELECT * FROM TripRecord WHERE eventId = :eventId")
fun queryTripRecordByEventId(eventId:String):Single<TripRecord>
@Insert
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(vararg tripRecord: TripRecord)
@Update

View File

@@ -14,44 +14,13 @@ import kotlin.random.Random
/**
* 出行动态fragment
*/
const val TAG = "TripRecordFragment"
class TripRecordFragment : MvpFragment<TripRecordFragment, TripRecordPresenter>() {
private val tripRecordList = ArrayList<TripRecord>()
override fun getLayoutId(): Int = R.layout.module_event_panel_fragment_trip_record
private val typeArray = arrayOf(V2XMessageEntity.V2XTypeEnum.ALERT_ROAD_WARNING, V2XMessageEntity.V2XTypeEnum.ALERT_ILLEGAL_PARK_WARNING, V2XMessageEntity.V2XTypeEnum.ALERT_SEEK_WARNING)
override fun initViews() {
btnInsert.setOnClickListener {
val randomId = Random.nextInt(10000)
val randomType = Random.nextInt(3)
val tripRecord = TripRecord(id = randomId, eventType = typeArray[randomType])
val random = Random.nextInt(10)
tripRecord.entity = "entity: $random"
tripRecord.recordTime = System.currentTimeMillis()
tripRecordList.add(tripRecord)
mPresenter.insertTripRecord(tripRecord)
Log.d(TAG, "insert over: $tripRecord")
}
btnDelete.setOnClickListener {
val random = Random.nextInt(tripRecordList.size)
val tripRecord = tripRecordList.removeAt(random)
mPresenter.deleteTripRecords(tripRecord)
Log.d(TAG, "delete over: $tripRecord")
}
btnUpdate.setOnClickListener {
val random = Random.nextInt(tripRecordList.size)
val tripRecord = tripRecordList[random]
Log.d(TAG, "before update: $tripRecord")
tripRecord.recordTime = System.currentTimeMillis()
mPresenter.updateTripRecords(tripRecord)
Log.d(TAG, "update over: $tripRecord")
}
btnQuery.setOnClickListener {
Log.d(TAG, "local list: $tripRecordList")
Log.d(MODULE_NAME, "local list: $tripRecordList")
mPresenter.queryAllTripRecord()
}
}
@@ -69,6 +38,5 @@ class TripRecordFragment : MvpFragment<TripRecordFragment, TripRecordPresenter>(
*/
fun refreshTripRecord(tripRecord: TripRecord) {
Logger.d(MODULE_NAME, "刷新单个出行动态: $tripRecord")
}
}

View File

@@ -0,0 +1,18 @@
package com.zhidao.mogo.module.event.panel.listener
import com.zhidao.mogo.module.event.panel.bean.TripRecord
/**
* 数据库异步操作数据回调
*/
interface ITripRecordCallback {
/**
* 查询全部出行动态成功
*/
fun queryTripRecordListSuccess(tripRecordList:List<TripRecord>)
/**
* 有出行动态新增或更新后,回调此接口
*/
fun insertOrUpdateTripRecordSuccess(tripRecord:TripRecord)
}

View File

@@ -1,162 +1,33 @@
package com.zhidao.mogo.module.event.panel.presenter
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.util.Log
import androidx.lifecycle.LifecycleOwner
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.mogo.commons.mvp.Presenter
import com.mogo.module.common.entity.V2XMessageEntity
import com.mogo.module.common.entity.V2XMessageEntity.V2XTypeEnum.*
import com.mogo.module.common.entity.V2XRoadEventEntity
import com.mogo.utils.ThreadPoolService
import com.mogo.utils.logger.Logger
import com.mogo.utils.network.utils.GsonUtil
import com.zhidao.mogo.module.event.panel.EventPanelConstants.MODULE_NAME
import com.zhidao.mogo.module.event.panel.bean.TripRecord
import com.zhidao.mogo.module.event.panel.dao.TripRecordDatabase
import com.zhidao.mogo.module.event.panel.fragment.TripRecordFragment
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import java.util.*
import com.zhidao.mogo.module.event.panel.listener.ITripRecordCallback
import com.zhidao.mogo.module.event.panel.util.TripRecordDataManager
private const val BROADCAST_SCENE_EVENT_ACTION = "com.v2x.scene_local_broadcast"
private const val BROADCAST_SCENE_MODIFY_ACTION = "com.zhidao.tanlu.dataerror"
private const val BROADCAST_SCENE_EXTRA_KEY = "V2XMessageEntity"
private const val BORADCAST_SCENE_MODIFY_EVENT_ID_KEY = "id"
private const val BROADCAST_SCENE_MODIFY_EVENT_UPDATE_TYPE_KEY = "updateType"
class TripRecordPresenter(view: TripRecordFragment) : Presenter<TripRecordFragment>(view) {
private val sceneEventReceiver = SceneEventReceiver()
private val tripRecordDao = TripRecordDatabase.getInstance(context).getTripRecordDao()
class TripRecordPresenter(view: TripRecordFragment) : Presenter<TripRecordFragment>(view),ITripRecordCallback {
init {
LocalBroadcastManager.getInstance(context).registerReceiver(sceneEventReceiver, IntentFilter(BROADCAST_SCENE_EVENT_ACTION))
context.registerReceiver(sceneEventReceiver, IntentFilter(BROADCAST_SCENE_MODIFY_ACTION))
}
private val compositeDisposable = CompositeDisposable()
fun queryAllTripRecord() {
val queryDisposable = tripRecordDao.queryAllTripRecord(countLimitTime()).subscribeOn(Schedulers.io()).observeOn(Schedulers.io()).map {
Logger.d(MODULE_NAME, "delete over time record when query thread is ${Thread.currentThread().name}")
tripRecordDao.deleteOvertimeTripRecord(countLimitTime())
it
}.observeOn(AndroidSchedulers.mainThread()).subscribe { it ->
Log.d(MODULE_NAME, "db query: $it, thread is ${Thread.currentThread().name}")
mView.refreshTripRecordList(it)
}
compositeDisposable.add(queryDisposable)
}
fun insertTripRecord(record: TripRecord) {
val disposable = Single.create<TripRecord> {
Logger.d(MODULE_NAME, "准备将数据插入数据库: $record")
tripRecordDao.insert(record)
it.onSuccess(record)
}.subscribeOn(Schedulers.io()).observeOn(Schedulers.io()).map {
// 为了防止只进不出,所以在插入新数据时,进行过期数据删除操作
Logger.d(MODULE_NAME, "delete over time record when insert: $it")
tripRecordDao.deleteOvertimeTripRecord(countLimitTime())
record
}.observeOn(AndroidSchedulers.mainThread()).subscribe{it->
Logger.d(MODULE_NAME, "插入+删除操作完成,做界面展示===$it")
mView.refreshTripRecord(it)
}
compositeDisposable.add(disposable)
}
fun updateTripRecords(vararg records: TripRecord) {
ThreadPoolService.execute {
tripRecordDao.update(*records)
}
}
fun deleteTripRecords(vararg records: TripRecord) {
ThreadPoolService.execute {
tripRecordDao.delete(*records)
}
}
/**
* 计算约束时间即当日0时
*/
private fun countLimitTime(): Long {
val calendar = Calendar.getInstance()
calendar.time = Date()
calendar.set(Calendar.HOUR_OF_DAY, 0)
calendar.set(Calendar.MINUTE, 0)
calendar.set(Calendar.SECOND, 0)
return calendar.timeInMillis
TripRecordDataManager.addTripRecordCallback(this)
}
override fun onDestroy(owner: LifecycleOwner) {
super.onDestroy(owner)
if(!compositeDisposable.isDisposed) {
compositeDisposable.dispose()
}
TripRecordDataManager.removeTripRecordCallback(this)
}
/**
* 处理道路事件推送,保存到本地数据库
* 目前只处理道路事件,违章提醒,他车求助,其他事件暂不处理
*/
private fun dealSceneMessage(type: Int, content: Any) {
if (type in arrayOf(ALERT_ROAD_WARNING, ALERT_ILLEGAL_PARK_WARNING, ALERT_SEEK_WARNING)) {
val eventId = if(type == ALERT_ROAD_WARNING){
val event = content as V2XRoadEventEntity
event.noveltyInfo.infoId
}else{
""
}
Logger.d(MODULE_NAME, "处理场景事件,准备插入数据库===eventId: $eventId")
insertTripRecord(TripRecord(id = content.hashCode(), eventId = eventId, eventType = type, entity = GsonUtil.jsonFromObject(content)))
}
fun queryAllTripRecord(){
TripRecordDataManager.queryAllTripRecord()
}
/**
* 本地数据库同步v2x传过来的纠错信息
*/
private fun syncRoadEventModifyState(eventId: String, modifyType: String) {
Logger.d(MODULE_NAME, "准备同步纠错信息: $eventId, $modifyType")
val disposable = tripRecordDao.queryTripRecordByEventId(eventId).subscribeOn(Schedulers.io()).observeOn(Schedulers.io()).map {
Logger.d(MODULE_NAME, "查询将纠错数据: $it")
it.usefulStatus = modifyType
it
}.map {
Logger.d(MODULE_NAME, "准备更新纠错数据: $it")
tripRecordDao.update(it)
it
}.observeOn(AndroidSchedulers.mainThread()).subscribe { it->
Logger.d(MODULE_NAME, "数据纠错更新完成,准备刷新界面==$it")
mView.refreshTripRecord(it)
}
compositeDisposable.add(disposable)
override fun queryTripRecordListSuccess(tripRecordList: List<TripRecord>) {
mView.refreshTripRecordList(tripRecordList)
}
inner class SceneEventReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Logger.d(MODULE_NAME, "收到V2X事件推送===")
when (intent.action) {
BROADCAST_SCENE_EVENT_ACTION -> {
// 道路事件推送
val message = intent.getSerializableExtra(BROADCAST_SCENE_EXTRA_KEY) as V2XMessageEntity<*>
Logger.d(MODULE_NAME, "道路事件推送 type: ${message.type}, content: ${message.content}")
dealSceneMessage(message.type, message.content)
}
BROADCAST_SCENE_MODIFY_ACTION -> {
// 纠错推送
syncRoadEventModifyState(intent.getStringExtra(BORADCAST_SCENE_MODIFY_EVENT_ID_KEY), intent.getStringExtra(BROADCAST_SCENE_MODIFY_EVENT_UPDATE_TYPE_KEY))
}
}
}
override fun insertOrUpdateTripRecordSuccess(tripRecord: TripRecord) {
mView.refreshTripRecord(tripRecord)
}
}

View File

@@ -0,0 +1,183 @@
package com.zhidao.mogo.module.event.panel.util
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.util.Log
import androidx.lifecycle.LifecycleOwner
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.mogo.module.common.entity.V2XMessageEntity
import com.mogo.module.common.entity.V2XMessageEntity.V2XTypeEnum.*
import com.mogo.module.common.entity.V2XRoadEventEntity
import com.mogo.utils.ThreadPoolService
import com.mogo.utils.logger.Logger
import com.mogo.utils.network.utils.GsonUtil
import com.zhidao.mogo.module.event.panel.EventPanelConstants.MODULE_NAME
import com.zhidao.mogo.module.event.panel.bean.TripRecord
import com.zhidao.mogo.module.event.panel.dao.TripRecordDao
import com.zhidao.mogo.module.event.panel.dao.TripRecordDatabase
import com.zhidao.mogo.module.event.panel.listener.ITripRecordCallback
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import java.util.*
import kotlin.collections.ArrayList
private const val BROADCAST_SCENE_EVENT_ACTION = "com.v2x.scene_local_broadcast"
private const val BROADCAST_SCENE_MODIFY_ACTION = "com.zhidao.tanlu.dataerror"
private const val BROADCAST_SCENE_EXTRA_KEY = "V2XMessageEntity"
private const val BORADCAST_SCENE_MODIFY_EVENT_ID_KEY = "id"
private const val BROADCAST_SCENE_MODIFY_EVENT_UPDATE_TYPE_KEY = "updateType"
/**
* 出行动态的数据管理类由于TripRecordFragment初始化时机较晚所以封装一个单例类提早初始化
*/
object TripRecordDataManager {
lateinit var context: Context
private val sceneEventReceiver = SceneEventReceiver()
private lateinit var tripRecordDao:TripRecordDao
private val tripRecordCallbackList = ArrayList<ITripRecordCallback>()
fun init(context: Context) {
this.context = context
LocalBroadcastManager.getInstance(context).registerReceiver(sceneEventReceiver, IntentFilter(BROADCAST_SCENE_EVENT_ACTION))
context.registerReceiver(sceneEventReceiver, IntentFilter(BROADCAST_SCENE_MODIFY_ACTION))
tripRecordDao = TripRecordDatabase.getInstance(TripRecordDataManager.context).getTripRecordDao()
}
fun addTripRecordCallback(callback: ITripRecordCallback) {
tripRecordCallbackList.add(callback)
}
fun removeTripRecordCallback(callback: ITripRecordCallback) {
tripRecordCallbackList.remove(callback)
}
private val compositeDisposable = CompositeDisposable()
fun queryAllTripRecord() {
val queryDisposable = tripRecordDao.queryAllTripRecord(countLimitTime()).subscribeOn(Schedulers.io()).observeOn(Schedulers.io()).map {
Logger.d(MODULE_NAME, "delete over time record when query thread is ${Thread.currentThread().name}")
tripRecordDao.deleteOvertimeTripRecord(countLimitTime())
it
}.observeOn(AndroidSchedulers.mainThread()).subscribe { it ->
Log.d(MODULE_NAME, "db query: $it, thread is ${Thread.currentThread().name}")
tripRecordCallbackList.forEach {callback->
callback.queryTripRecordListSuccess(it)
}
}
compositeDisposable.add(queryDisposable)
}
private fun insertTripRecord(record: TripRecord) {
val disposable = Single.create<TripRecord> {
Logger.d(MODULE_NAME, "准备将数据插入数据库: $record")
tripRecordDao.insert(record)
it.onSuccess(record)
}.subscribeOn(Schedulers.io()).observeOn(Schedulers.io()).map {
// 为了防止只进不出,所以在插入新数据时,进行过期数据删除操作
Logger.d(MODULE_NAME, "delete over time record when insert: $it")
tripRecordDao.deleteOvertimeTripRecord(countLimitTime())
record
}.observeOn(AndroidSchedulers.mainThread()).subscribe{ it->
Logger.d(MODULE_NAME, "插入+删除操作完成,做界面展示===$it")
tripRecordCallbackList.forEach { callback->
callback.insertOrUpdateTripRecordSuccess(it)
}
}
compositeDisposable.add(disposable)
}
fun updateTripRecords(vararg records: TripRecord) {
ThreadPoolService.execute {
tripRecordDao.update(*records)
}
}
fun deleteTripRecords(vararg records: TripRecord) {
ThreadPoolService.execute {
tripRecordDao.delete(*records)
}
}
/**
* 计算约束时间即当日0时
*/
private fun countLimitTime(): Long {
val calendar = Calendar.getInstance()
calendar.time = Date()
calendar.set(Calendar.HOUR_OF_DAY, 0)
calendar.set(Calendar.MINUTE, 0)
calendar.set(Calendar.SECOND, 0)
return calendar.timeInMillis
}
fun release(owner: LifecycleOwner) {
if(!compositeDisposable.isDisposed) {
compositeDisposable.dispose()
}
}
/**
* 处理道路事件推送,保存到本地数据库
* 目前只处理道路事件,违章提醒,他车求助,其他事件暂不处理
*/
private fun dealSceneMessage(type: Int, content: Any) {
if (type in arrayOf(ALERT_ROAD_WARNING, ALERT_ILLEGAL_PARK_WARNING, ALERT_SEEK_WARNING)) {
val eventId = if(type == V2XMessageEntity.V2XTypeEnum.ALERT_ROAD_WARNING){
val event = content as V2XRoadEventEntity
event.noveltyInfo.infoId
}else{
""
}
Logger.d(MODULE_NAME, "处理场景事件,准备插入数据库===eventId: $eventId")
insertTripRecord(TripRecord(id = content.hashCode(), eventId = eventId, eventType = type, entity = GsonUtil.jsonFromObject(content)))
}
}
/**
* 本地数据库同步v2x传过来的纠错信息
*/
private fun syncRoadEventModifyState(eventId: String, modifyType: String) {
Logger.d(MODULE_NAME, "准备同步纠错信息: $eventId, $modifyType")
val disposable = tripRecordDao.queryTripRecordByEventId(eventId).subscribeOn(Schedulers.io()).observeOn(Schedulers.io()).map {
Logger.d(MODULE_NAME, "查询将纠错数据: $it")
it.usefulStatus = modifyType
it
}.map {
Logger.d(MODULE_NAME, "准备更新纠错数据: $it")
tripRecordDao.update(it)
it
}.observeOn(AndroidSchedulers.mainThread()).subscribe { it->
Logger.d(MODULE_NAME, "数据纠错更新完成,准备刷新界面==$it")
tripRecordCallbackList.forEach { callback->
callback.insertOrUpdateTripRecordSuccess(it)
}
}
compositeDisposable.add(disposable)
}
class SceneEventReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Logger.d(MODULE_NAME, "收到V2X事件推送===")
when (intent.action) {
BROADCAST_SCENE_EVENT_ACTION -> {
// 道路事件推送
val message = intent.getSerializableExtra(BROADCAST_SCENE_EXTRA_KEY) as V2XMessageEntity<*>
Logger.d(MODULE_NAME, "道路事件推送 type: ${message.type}, content: ${message.content}")
dealSceneMessage(message.type, message.content)
}
BROADCAST_SCENE_MODIFY_ACTION -> {
// 纠错推送
syncRoadEventModifyState(intent.getStringExtra(BORADCAST_SCENE_MODIFY_EVENT_ID_KEY), intent.getStringExtra(BROADCAST_SCENE_MODIFY_EVENT_UPDATE_TYPE_KEY))
}
}
}
}
}

View File

@@ -10,7 +10,7 @@ import kotlinx.android.synthetic.main.module_left_panel_simple_speed.*
*
* @author tongchenfei
*/
private const val SPEED_THRESHOLD = 90
private const val SPEED_THRESHOLD = 40
class SimpleSpeedFragment: MvpFragment<SimpleSpeedFragment, SimpleSpeedPresenter>() {
override fun getLayoutId(): Int {
return R.layout.module_left_panel_simple_speed

View File

@@ -29,4 +29,16 @@
android:textColor="#fff"
android:background="@drawable/module_left_panel_normal_speed_bg" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="当前车速"
android:textColor="#fff"
android:textStyle="bold"
app:layout_constraintLeft_toLeftOf="@id/tvModuleLeftPanelSpeed"
app:layout_constraintRight_toRightOf="@id/tvModuleLeftPanelSpeed"
app:layout_constraintTop_toBottomOf="@id/tvModuleLeftPanelSpeed"
android:layout_marginTop="@dimen/module_left_panel_simple_speed_title_margin"
android:textSize="@dimen/module_left_panel_simple_speed_title_size" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -2,4 +2,7 @@
<resources>
<dimen name="module_left_panel_simple_speed_text_size">80px</dimen>
<dimen name="module_left_panel_simple_speed_text_margin_top">69.6px</dimen>
<dimen name="module_left_panel_simple_speed_title_size">20px</dimen>
<dimen name="module_left_panel_simple_speed_title_margin">28px</dimen>
</resources>