opt 出行面板本地数据存储

This commit is contained in:
tongchenfei
2020-07-08 18:23:30 +08:00
parent 8d8c57269e
commit 0ad8e55f8e
10 changed files with 209 additions and 46 deletions

View File

@@ -8,4 +8,8 @@ package com.zhidao.mogo.module.event.panel
object EventPanelConstants {
const val MODULE_NAME = "MODULE_EVENT_PANEL"
const val PATH_NAME = "/event/panel"
const val ROAD_EVENT_USEFUL = "2"
const val ROAD_EVENT_UNUSEFUL = "1"
const val ROAD_EVENT_USEFUL_STATUS_UNSET = "0"
}

View File

@@ -46,6 +46,10 @@ class EventPanelModuleProvider : IEventPanelProvider {
EventPanelFragment.getInstance().showPanel()
}
override fun isPanelShow(): Boolean {
return EventPanelFragment.getInstance().isPanelShow()
}
/**
* 隐藏面板

View File

@@ -2,16 +2,24 @@ package com.zhidao.mogo.module.event.panel.bean
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.zhidao.mogo.module.event.panel.EventPanelConstants.ROAD_EVENT_USEFUL_STATUS_UNSET
/**
* 出行记录本地存储封装类
* 出行记录本地存储封装类,此类标识了数据库表名以及字段名
*
* @author
* @author tongchenfei
*/
@Entity
data class TripRecord(@PrimaryKey(autoGenerate = false)
var eventType:Int,
var canUsed: Boolean = true,
var isUsed: Boolean = false,
var entity: String? = null,
var recordTime: Long = 0)
var id: Int,
var eventId: String = "",
var eventType: Int,
/**
* 是否有用
* 1 - 没用
* 2 - 有用
* 0 - 未设置
*/
var usefulStatus: String = ROAD_EVENT_USEFUL_STATUS_UNSET,
var entity: String = "",
var recordTime: Long = System.currentTimeMillis())

View File

@@ -10,7 +10,15 @@ interface TripRecordDao {
* @param limitTime 当日0点的时间戳
*/
@Query(value = "SELECT * FROM TripRecord WHERE recordTime > :limitTime ORDER BY recordTime DESC")
fun getAllTripRecord(limitTime:Long):Single<List<TripRecord>>
fun queryAllTripRecord(limitTime:Long):Single<List<TripRecord>>
/**
* 根据事件id获取出行动态
*
* @param eventId 事件id [com.mogo.module.common.entity.V2XRoadEventEntity.noveltyInfo.infoId]
*/
@Query(value = "SELECT * FROM TripRecord WHERE eventId = :eventId")
fun queryTripRecordByEventId(eventId:String):Single<TripRecord>
@Insert
fun insert(vararg tripRecord: TripRecord)

View File

@@ -31,7 +31,13 @@ class EventPanelFragment : MvpFragment<EventPanelFragment, EventPanelPresenter>(
override fun initViews() {
Logger.d(MODULE_NAME, "EventPanelFragment init view===")
vpEventPanel.adapter = EventPagerAdapter(this)
btnShowOrHidePanels.setOnClickListener {
if (vpEventPanel.visibility == View.GONE) {
showPanel()
}else{
hidePanel()
}
}
}
override fun createPresenter(): EventPanelPresenter {
return EventPanelPresenter(this)
@@ -39,11 +45,17 @@ class EventPanelFragment : MvpFragment<EventPanelFragment, EventPanelPresenter>(
fun showPanel(){
Logger.d(MODULE_NAME,"in fragment show panel")
clPanelContainer.visibility = View.VISIBLE
vpEventPanel.visibility = View.VISIBLE
btnShowOrHidePanels.text = "隐藏面板"
}
fun hidePanel(){
Logger.d(MODULE_NAME,"in fragment hide panel")
clPanelContainer.visibility = View.GONE
vpEventPanel.visibility = View.GONE
btnShowOrHidePanels.text = "显示面板"
}
fun isPanelShow():Boolean{
return vpEventPanel.visibility == View.VISIBLE
}
}

View File

@@ -2,6 +2,7 @@ package com.zhidao.mogo.module.event.panel.fragment
import android.util.Log
import com.mogo.commons.mvp.MvpFragment
import com.mogo.module.common.entity.V2XMessageEntity
import com.mogo.utils.logger.Logger
import com.zhidao.mogo.module.event.panel.EventPanelConstants.MODULE_NAME
import com.zhidao.mogo.module.event.panel.R
@@ -14,14 +15,17 @@ import kotlin.random.Random
* 出行动态fragment
*/
const val TAG = "TripRecordFragment"
class TripRecordFragment: MvpFragment<TripRecordFragment, TripRecordPresenter>() {
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 randomType = Random.nextInt(10000)
val tripRecord = TripRecord(randomType)
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()
@@ -40,7 +44,7 @@ class TripRecordFragment: MvpFragment<TripRecordFragment, TripRecordPresenter>()
btnUpdate.setOnClickListener {
val random = Random.nextInt(tripRecordList.size)
val tripRecord = tripRecordList[random]
Log.d(TAG,"before update: $tripRecord")
Log.d(TAG, "before update: $tripRecord")
tripRecord.recordTime = System.currentTimeMillis()
mPresenter.updateTripRecords(tripRecord)
Log.d(TAG, "update over: $tripRecord")
@@ -52,11 +56,19 @@ class TripRecordFragment: MvpFragment<TripRecordFragment, TripRecordPresenter>()
}
}
override fun createPresenter(): TripRecordPresenter = TripRecordPresenter(this)
override fun createPresenter(): TripRecordPresenter = TripRecordPresenter(this)
fun refreshTripRecord(tripRecords: List<TripRecord>) {
Logger.d(MODULE_NAME, "刷新出行动态:$tripRecords")
fun refreshTripRecordList(tripRecords: List<TripRecord>) {
Logger.d(MODULE_NAME, "刷新出行动态列表$tripRecords")
tripRecordList.clear()
tripRecordList.addAll(tripRecords)
}
/**
* 刷新单个出行动态,如果无此动态,新增动态
*/
fun refreshTripRecord(tripRecord: TripRecord) {
Logger.d(MODULE_NAME, "刷新单个出行动态: $tripRecord")
}
}

View File

@@ -1,71 +1,162 @@
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.Disposable
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import java.util.*
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) {
var queryDisposable:Disposable? = null
private val sceneEventReceiver = SceneEventReceiver()
private val tripRecordDao = TripRecordDatabase.getInstance(context).getTripRecordDao()
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() {
queryDisposable = TripRecordDatabase.getInstance(context).getTripRecordDao().getAllTripRecord(countLimitTime()).subscribeOn(Schedulers.io()).observeOn(Schedulers.io()).map {
Logger.d(MODULE_NAME,"delete over time record when query thread is ${Thread.currentThread().name}")
TripRecordDatabase.getInstance(context).getTripRecordDao().deleteOvertimeTripRecord(countLimitTime())
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->
}.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 insertTripRecord(vararg records: TripRecord) {
fun updateTripRecords(vararg records: TripRecord) {
ThreadPoolService.execute {
TripRecordDatabase.getInstance(context).getTripRecordDao().insert(*records)
// 为了防止只进不出,所以在插入新数据时,进行过期数据删除操作
Logger.d(MODULE_NAME,"delete over time record when insert")
TripRecordDatabase.getInstance(context).getTripRecordDao().deleteOvertimeTripRecord(countLimitTime())
tripRecordDao.update(*records)
}
}
fun updateTripRecords(vararg records: TripRecord) {
fun deleteTripRecords(vararg records: TripRecord) {
ThreadPoolService.execute {
TripRecordDatabase.getInstance(context).getTripRecordDao().update(*records)
}
}
fun deleteTripRecords(vararg records: TripRecord) {
ThreadPoolService.execute {
TripRecordDatabase.getInstance(context).getTripRecordDao().delete(*records)
tripRecordDao.delete(*records)
}
}
/**
* 计算约束时间即当日0时
*/
private fun countLimitTime():Long{
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)
calendar.set(Calendar.HOUR_OF_DAY, 0)
calendar.set(Calendar.MINUTE, 0)
calendar.set(Calendar.SECOND, 0)
return calendar.timeInMillis
}
override fun onDestroy(owner: LifecycleOwner) {
super.onDestroy(owner)
queryDisposable?.let {
if (!it.isDisposed) {
it.dispose()
}
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 == 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")
mView.refreshTripRecord(it)
}
compositeDisposable.add(disposable)
}
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))
}
}
}
}
}

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/clPanelContainer"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -7,5 +8,18 @@
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/vpEventPanel"
android:layout_width="match_parent"
android:layout_height="match_parent" />
android:layout_height="match_parent"
android:visibility="gone"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btnShowOrHidePanels"
android:text="显示面板"
android:textSize="20sp"
android:textColor="#000"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="10dp"
android:layout_marginEnd="10dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -21,6 +21,7 @@
android:text="Insert"
android:textColor="#000"
android:textSize="30sp"
android:layout_marginTop="100dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/btnUpdate"
app:layout_constraintTop_toTopOf="parent" />
@@ -32,6 +33,7 @@
android:text="Update"
android:textColor="#000"
android:textSize="30sp"
android:layout_marginTop="100dp"
app:layout_constraintLeft_toRightOf="@+id/btnInsert"
app:layout_constraintRight_toLeftOf="@+id/btnDelete"
app:layout_constraintTop_toTopOf="parent" />
@@ -43,6 +45,7 @@
android:text="Delete"
android:textColor="#000"
android:textSize="30sp"
android:layout_marginTop="100dp"
app:layout_constraintLeft_toRightOf="@+id/btnUpdate"
app:layout_constraintRight_toLeftOf="@+id/btnQuery"
app:layout_constraintTop_toTopOf="parent" />
@@ -54,6 +57,7 @@
android:text="Query"
android:textColor="#000"
android:textSize="30sp"
android:layout_marginTop="100dp"
app:layout_constraintLeft_toRightOf="@+id/btnDelete"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />

View File

@@ -17,4 +17,10 @@ public interface IEventPanelProvider extends IMogoModuleProvider {
* 隐藏面板
*/
void hidePanel();
/**
* 面板是否在展示
* @return true-正在展示 false-未展示
*/
boolean isPanelShow();
}