refactor(user): 重构司机信息存储逻辑

- 将司机信息从 MMKV 迁移到 Room 数据库
- 新增 DriverInfoBean 实体类和 DriverInfoDao接口
- 更新 GlobalData 中的 driverInfo 相关逻辑- 修改相关 Activity 和 ViewModel 中的代码,使用新的数据库存储方式- 优化了司机信息的获取和更新流程
This commit is contained in:
songzhiling
2025-04-16 15:58:07 +08:00
parent d2f2752499
commit 0f24648cb1
53 changed files with 1259 additions and 1272 deletions

View File

@ -4,10 +4,9 @@ import android.app.Application
import com.amap.api.location.AMapLocation
import com.blankj.utilcode.util.AppUtils
import com.tencent.mmkv.MMKV
import com.za.bean.DriverInfo
import com.za.bean.VehicleInfo
import com.za.bean.db.order.OrderInfo
import com.za.room.RoomHelper
import com.za.room.db.user.DriverInfoBean
object GlobalData {
lateinit var application : Application
@ -16,20 +15,19 @@ object GlobalData {
var token : String? = null
get() {
return MMKV.defaultMMKV().decodeString("TOKEN", null)
return MMKV.defaultMMKV().decodeString("ZD_TOKEN", null)
}
set(value) {
MMKV.defaultMMKV().encode("TOKEN", value)
MMKV.defaultMMKV().encode("ZD_TOKEN", value)
field = value
}
//记录上次登录的手机号
var lastLoginPhone : String? = null
var regid : String? = null
get() {
return MMKV.defaultMMKV().decodeString("lastLoginPhone", null)
return MMKV.defaultMMKV().decodeString("regid", null)
}
set(value) {
MMKV.defaultMMKV().encode("lastLoginPhone", value)
MMKV.defaultMMKV().encode("regid", value)
field = value
}
@ -42,25 +40,19 @@ object GlobalData {
field = value
}
var driverInfo : DriverInfo? = null
//新订单是否已经被处理
var isHandlerNewOrder : Boolean? = false
var driverInfoBean : DriverInfoBean? = null
get() {
return MMKV.defaultMMKV().decodeParcelable("driverInfo", DriverInfo::class.java)
val driverInfoBean = RoomHelper.db?.driverInfoDao()?.getDriverInfoFromUserId()
field = driverInfoBean
return driverInfoBean
}
set(value) {
MMKV.defaultMMKV().encode("driverInfo", value)
field = value
RoomHelper.db?.driverInfoDao()?.updateDriverInfo(value)
}
var vehicleInfo : VehicleInfo? = null
get() {
return MMKV.defaultMMKV().decodeParcelable("vehicleInfo", VehicleInfo::class.java)
}
set(value) {
MMKV.defaultMMKV().encode("vehicleInfo", value)
field = value
}
var currentOrder : OrderInfo? = null
get() {
return MMKV.defaultMMKV().decodeParcelable("currentOrder", OrderInfo::class.java)
@ -77,11 +69,10 @@ object GlobalData {
var currentLocation : AMapLocation? = null
get() {
return MMKV.defaultMMKV().decodeParcelable("currentLocation", AMapLocation::class.java)
return field
}
set(value) {
value?.time = System.currentTimeMillis()
MMKV.defaultMMKV().encode("currentLocation", value)
field = value
}
@ -97,8 +88,6 @@ object GlobalData {
fun clearUserCache() {
token = null
aesKey = null
driverInfo = null
vehicleInfo = null
currentLocation = null
loginTime = null
}

View File

@ -3,7 +3,6 @@ package com.za.common
import android.app.Application
import com.tencent.bugly.Bugly
import com.tencent.mmkv.MMKV
import com.tencent.mmkv.MMKVLogLevel
import com.za.base.AppConfig
import com.za.common.log.LogUtil
import com.za.room.RoomHelper
@ -11,6 +10,7 @@ import com.za.service.location.ZdLocationManager
object ZDManager {
lateinit var application : Application
fun init(application : Application, isRelease : Boolean = false) {
this.application = application
thirdSdkInit(isRelease)
@ -22,11 +22,12 @@ object ZDManager {
} else {
AppConfig.crm1()
}
GlobalData.application = application
MMKV.initialize(application, MMKVLogLevel.LevelInfo)
GlobalData.application = application // 在 Application 中初始化 MMKV所有进程共享同一存储路径
val rootDir = application.filesDir.absolutePath + "/mmkv"
MMKV.initialize(application, rootDir)
Bugly.init(application, "6972a6b56d", true)
LogUtil.init(application)
RoomHelper.init(application)
ZdLocationManager.init(application)
}
}
}

View File

@ -15,7 +15,6 @@ import com.blankj.utilcode.util.FileUtils
import com.blankj.utilcode.util.TimeUtils
import com.za.common.GlobalData
import com.za.common.util.AppFileManager
import com.za.servicing.BuildConfig
import io.reactivex.rxjava3.schedulers.Schedulers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@ -40,278 +39,272 @@ import java.util.concurrent.atomic.AtomicBoolean
import kotlin.concurrent.thread
object LogUtil {
private var context: Application? = null
private var logDestinationPath: String? = null
private var orderLogDirPath: String? = null
private var normalLogDirPath: String? = null
private val coroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
private val logBuffer = StringBuilder()
private val isWriting = AtomicBoolean(false)
fun init(context: Application) {
this.context = context
logDestinationPath = AppFileManager.getLogPath(context).also { path ->
createDirectoryIfNotExists(path)
orderLogDirPath = "$path${File.separator}order_log".also { createDirectoryIfNotExists(it) }
normalLogDirPath = "$path${File.separator}normal_log".also { createDirectoryIfNotExists(it) }
}
private var context : Application? = null
private var logDestinationPath : String? = null
private var orderLogDirPath : String? = null
private var normalLogDirPath : String? = null
private val coroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
private val logBuffer = StringBuilder()
private val isWriting = AtomicBoolean(false)
initializeWorkManager(context)
}
fun init(context : Application) {
this.context = context
private fun createDirectoryIfNotExists(path: String) {
File(path).apply { if (!exists()) mkdir() }
}
logDestinationPath = AppFileManager.getLogPath(context).also { path ->
createDirectoryIfNotExists(path)
orderLogDirPath =
"$path${File.separator}order_log".also { createDirectoryIfNotExists(it) }
normalLogDirPath =
"$path${File.separator}normal_log".also { createDirectoryIfNotExists(it) }
}
private fun initializeWorkManager(context: Application) {
if (!WorkManager.isInitialized()) {
WorkManager.initialize(context, Configuration.Builder()
.setMinimumLoggingLevel(Log.INFO)
.build())
}
initializeWorkManager(context)
}
WorkManager.getInstance(context).apply {
cancelAllWorkByTag("logWorkRequest")
enqueue(PeriodicWorkRequest.Builder(LogTask::class.java, 20, TimeUnit.MINUTES)
.addTag("logWorkRequest")
.build())
}
}
private fun createDirectoryIfNotExists(path : String) {
File(path).apply { if (! exists()) mkdir() }
}
fun print(tag: String, content: String) {
val time = getCurrentTime()
val logEntry = "$time---$tag---$content\n"
if (BuildConfig.DEBUG) {
Log.e("normal", "$tag---$content")
}
synchronized(logBuffer) {
logBuffer.append(logEntry)
}
if (logBuffer.length > 4096) {
coroutineScope.launch {
flushBuffer()
}
}
}
private fun initializeWorkManager(context : Application) {
if (! WorkManager.isInitialized()) {
WorkManager.initialize(context,
Configuration.Builder().setMinimumLoggingLevel(Log.INFO).build())
}
fun print(tag: String, throwable: Throwable) {
val content = StringWriter()
val printWriter = PrintWriter(content)
throwable.printStackTrace(printWriter)
print(tag, content.toString())
}
WorkManager.getInstance(context).apply {
cancelAllWorkByTag("logWorkRequest")
enqueue(PeriodicWorkRequest.Builder(LogTask::class.java, 20, TimeUnit.MINUTES)
.addTag("logWorkRequest").build())
}
}
private suspend fun flushBuffer() = withContext(Dispatchers.IO) {
if (!isWriting.compareAndSet(false, true)) return@withContext
fun print(tag : String, content : String) {
val time = getCurrentTime()
val logEntry = "$time---$tag---$content\n"
Log.e("normal", "$tag---$content")
synchronized(logBuffer) {
logBuffer.append(logEntry)
}
val logContent: String
synchronized(logBuffer) {
if (logBuffer.isEmpty()) {
isWriting.set(false)
return@withContext
}
logContent = logBuffer.toString()
logBuffer.clear()
}
if (logBuffer.length > 4096) {
coroutineScope.launch {
flushBuffer()
}
}
}
try {
val fileName = "normal_log.txt"
val logFile = File("$normalLogDirPath${File.separator}$fileName")
fun print(tag : String, throwable : Throwable) {
val content = StringWriter()
val printWriter = PrintWriter(content)
throwable.printStackTrace(printWriter)
print(tag, content.toString())
}
logFile.parentFile?.mkdirs()
private suspend fun flushBuffer() = withContext(Dispatchers.IO) {
if (! isWriting.compareAndSet(false, true)) return@withContext
if (!logFile.exists()) {
logFile.createNewFile()
addLogHead(logFile, getCurrentTime())
}
val logContent : String
synchronized(logBuffer) {
if (logBuffer.isEmpty()) {
isWriting.set(false)
return@withContext
}
logContent = logBuffer.toString()
logBuffer.clear()
}
BufferedWriter(FileWriter(logFile, true)).use { writer ->
writer.write(logContent)
writer.flush()
}
try {
val fileName = "normal_log.txt"
val logFile = File("$normalLogDirPath${File.separator}$fileName")
if (logFile.length() >= 8 * MemoryConstants.MB) {
rotateLogFile(logFile)
}
} catch (e: IOException) {
Log.e("LogUtil", "Error in flushBuffer: ${e.message}")
} catch (e: Exception) {
Log.e("LogUtil", "Error in flushBuffer: ${e.message}")
} finally {
isWriting.set(false)
}
}
logFile.parentFile?.mkdirs()
private fun rotateLogFile(file: File) {
if (!file.exists()) return
val newFileName = buildString {
append(AppUtils.getAppVersionCode())
append("_")
append(GlobalData.vehicleInfo?.vehicleName ?: "unknown")
append("_")
append(GlobalData.driverInfo?.userName ?: "unknown")
append("_")
append(TimeUtils.getNowString())
append(".txt")
}
val newFile = File("$normalLogDirPath${File.separator}$newFileName")
try {
if (file.renameTo(newFile)) {
compressAndUploadLog(newFile)
// 创建新的日志文件
file.createNewFile()
addLogHead(file, getCurrentTime())
} else {
print("LogUtil", "Failed to rename log file")
}
} catch (e: Exception) {
print("LogUtil", "Error during log rotation: ${e.message}")
}
}
if (! logFile.exists()) {
logFile.createNewFile()
addLogHead(logFile, getCurrentTime())
}
private fun compressAndUploadLog(logFile: File) = coroutineScope.launch {
try {
val compressedFile = File("${logFile.absolutePath}.7z")
compress(logFile, compressedFile.absolutePath)
upload(logFile, compressedFile)
} catch (e: Exception) {
print("LogUtil", e.toString())
}
}
BufferedWriter(FileWriter(logFile, true)).use { writer ->
writer.write(logContent)
writer.flush()
}
private fun deleteLog(file: File) {
try {
FileUtils.delete(file.absolutePath)
} catch (e: Exception) {
e.printStackTrace()
}
}
if (logFile.length() >= 8 * MemoryConstants.MB) {
rotateLogFile(logFile)
}
} catch (e : IOException) {
Log.e("LogUtil", "Error in flushBuffer: ${e.message}")
} catch (e : Exception) {
Log.e("LogUtil", "Error in flushBuffer: ${e.message}")
} finally {
isWriting.set(false)
}
}
fun updateNormalLog() {
thread {
if (GlobalData.token.isNullOrBlank()) {
return@thread
}
val fileName = "normal_log.txt"
val file = File("$normalLogDirPath${File.separator}$fileName")
val reName = "${AppUtils.getAppVersionCode()}_${GlobalData.vehicleInfo?.vehicleName}_${GlobalData.driverInfo?.userName}_${TimeUtils.getNowString()}.txt"
val reNamePath = "$normalLogDirPath${File.separator}$reName"
file.renameTo(File(reNamePath))
normalLogDirPath?.let { it ->
File(it).listFiles()?.forEach {
if (it.length() / MemoryConstants.MB >= 10) {
deleteLog(it)
return@thread
}
if (it.exists() && !it.name.contains("normal_log")) {
if (it.name.contains("7z")) {
upload(null, desFile = it)
} else {
val zipNamePath = it.absolutePath + ".7z"
val zipFile = File(zipNamePath)
if (!zipFile.exists()) {
try {
zipFile.createNewFile()
} catch (e: IOException) {
e.printStackTrace()
}
}
compress(it, zipNamePath)
}
}
}
}
}
}
private fun rotateLogFile(file : File) {
if (! file.exists()) return
private fun compress(srcFile: File, desFilePath: String) {
try {
val out = XZCompressorOutputStream(FileOutputStream(desFilePath))
addToArchiveCompression(out, srcFile, File(desFilePath))
} catch (e: Exception) {
e.printStackTrace()
}
}
val newFileName = buildString {
append(AppUtils.getAppVersionCode())
append("_")
append(GlobalData.driverInfoBean?.vehicleName ?: "unknown")
append("_")
append(GlobalData.driverInfoBean?.userName ?: "unknown")
append("_")
append(TimeUtils.getNowString())
append(".txt")
}
private fun addToArchiveCompression(
sevenZOutputFile: XZCompressorOutputStream,
srcFile: File, desFile: File
) {
if (srcFile.isFile) {
var inputStream: FileInputStream? = null
try {
inputStream = FileInputStream(srcFile)
val b = ByteArray(2048)
var count: Int
while (inputStream.read(b).also { count = it } != -1) {
sevenZOutputFile.write(b, 0, count)
}
sevenZOutputFile.close()
inputStream.close()
upload(srcFile, desFile)
} catch (e: Exception) {
e.printStackTrace()
} finally {
try {
sevenZOutputFile.close()
inputStream!!.close()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
val newFile = File("$normalLogDirPath${File.separator}$newFileName")
private fun upload(srcFile: File?, desFile: File) {
val requestBody: RequestBody = desFile.asRequestBody("multipart/form-data".toMediaType())
val part = MultipartBody.Part.createFormData("file", desFile.name, requestBody)
try {
if (file.renameTo(newFile)) {
compressAndUploadLog(newFile) // 创建新的日志文件
file.createNewFile()
addLogHead(file, getCurrentTime())
} else {
print("LogUtil", "Failed to rename log file")
}
} catch (e : Exception) {
print("LogUtil", "Error during log rotation: ${e.message}")
}
}
val disposable = LogRetrofitHelper.getDefaultService()
.uploadLog(part, desFile.name, "rescue-app")
.subscribeOn(Schedulers.io())
.subscribe({ it ->
if (it.code == 200) {
deleteLog(desFile)
}
srcFile?.let {
deleteLog(it)
}
}, {
}, {})
}
private fun compressAndUploadLog(logFile : File) = coroutineScope.launch {
try {
val compressedFile = File("${logFile.absolutePath}.7z")
compress(logFile, compressedFile.absolutePath)
upload(logFile, compressedFile)
} catch (e : Exception) {
print("LogUtil", e.toString())
}
}
private fun addLogHead(file: File, time: String) {
file.appendBytes("${time}---应用版本---${AppUtils.getAppVersionName()}".toByteArray())
file.appendBytes("\n".toByteArray())
file.appendBytes("$time---系统版本---Android${DeviceUtils.getSDKVersionName()} ${DeviceUtils.getSDKVersionCode()}".toByteArray())
file.appendBytes("\n".toByteArray())
file.appendBytes("$time---ROM---${DeviceUtils.getManufacturer()} ${DeviceUtils.getModel()}".toByteArray())
file.appendBytes("\n".toByteArray())
file.appendBytes("$time---build---${AppUtils.getAppVersionCode()}".toByteArray())
file.appendBytes("\n".toByteArray())
file.appendBytes("$time---APP名称---中道救援-司机端".toByteArray())
file.appendBytes("\n".toByteArray())
file.appendBytes("$time---车辆名称---${GlobalData.vehicleInfo?.vehicleName}".toByteArray())
file.appendBytes("\n".toByteArray())
file.appendBytes("$time---司机名称---${GlobalData.driverInfo?.userName ?: GlobalData.vehicleInfo?.userName}".toByteArray())
file.appendBytes("\n".toByteArray())
}
private fun deleteLog(file : File) {
try {
FileUtils.delete(file.absolutePath)
} catch (e : Exception) {
e.printStackTrace()
}
}
private fun getCurrentTime(): String {
return TimeUtils.millis2String(System.currentTimeMillis(), "yyyy/MM/dd HH:mm:ss.SSS")
}
fun updateNormalLog() {
thread {
if (GlobalData.token.isNullOrBlank()) {
return@thread
}
val fileName = "normal_log.txt"
val file = File("$normalLogDirPath${File.separator}$fileName")
val reName =
"${AppUtils.getAppVersionCode()}_${GlobalData.driverInfoBean?.vehicleName}_${GlobalData.driverInfoBean?.userName}_${TimeUtils.getNowString()}.txt"
val reNamePath = "$normalLogDirPath${File.separator}$reName"
file.renameTo(File(reNamePath))
normalLogDirPath?.let { it ->
File(it).listFiles()?.forEach {
if (it.length() / MemoryConstants.MB >= 10) {
deleteLog(it)
return@thread
}
if (it.exists() && ! it.name.contains("normal_log")) {
if (it.name.contains("7z")) {
upload(null, desFile = it)
} else {
val zipNamePath = it.absolutePath + ".7z"
val zipFile = File(zipNamePath)
if (! zipFile.exists()) {
try {
zipFile.createNewFile()
} catch (e : IOException) {
e.printStackTrace()
}
}
compress(it, zipNamePath)
}
}
}
}
}
}
class LogTask(appContext: Context, workerParams: WorkerParameters) : Worker(appContext, workerParams) {
override fun doWork(): Result {
updateNormalLog()
return Result.success()
}
}
private fun compress(srcFile : File, desFilePath : String) {
try {
val out = XZCompressorOutputStream(FileOutputStream(desFilePath))
addToArchiveCompression(out, srcFile, File(desFilePath))
} catch (e : Exception) {
e.printStackTrace()
}
}
private fun addToArchiveCompression(sevenZOutputFile : XZCompressorOutputStream,
srcFile : File,
desFile : File) {
if (srcFile.isFile) {
var inputStream : FileInputStream? = null
try {
inputStream = FileInputStream(srcFile)
val b = ByteArray(2048)
var count : Int
while (inputStream.read(b).also { count = it } != - 1) {
sevenZOutputFile.write(b, 0, count)
}
sevenZOutputFile.close()
inputStream.close()
upload(srcFile, desFile)
} catch (e : Exception) {
e.printStackTrace()
} finally {
try {
sevenZOutputFile.close()
inputStream !!.close()
} catch (e : Exception) {
e.printStackTrace()
}
}
}
}
private fun upload(srcFile : File?, desFile : File) {
val requestBody : RequestBody = desFile.asRequestBody("multipart/form-data".toMediaType())
val part = MultipartBody.Part.createFormData("file", desFile.name, requestBody)
val disposable =
LogRetrofitHelper.getDefaultService().uploadLog(part, desFile.name, "rescue-app")
.subscribeOn(Schedulers.io()).subscribe({ it ->
if (it.code == 200) {
deleteLog(desFile)
}
srcFile?.let {
deleteLog(it)
}
}, {}, {})
}
private fun addLogHead(file : File, time : String) {
file.appendBytes("${time}---应用版本---${AppUtils.getAppVersionName()}".toByteArray())
file.appendBytes("\n".toByteArray())
file.appendBytes("$time---系统版本---Android${DeviceUtils.getSDKVersionName()} ${DeviceUtils.getSDKVersionCode()}".toByteArray())
file.appendBytes("\n".toByteArray())
file.appendBytes("$time---ROM---${DeviceUtils.getManufacturer()} ${DeviceUtils.getModel()}".toByteArray())
file.appendBytes("\n".toByteArray())
file.appendBytes("$time---build---${AppUtils.getAppVersionCode()}".toByteArray())
file.appendBytes("\n".toByteArray())
file.appendBytes("$time---APP名称---中道救援-司机端".toByteArray())
file.appendBytes("\n".toByteArray())
file.appendBytes("$time---车辆名称---${GlobalData.driverInfoBean?.vehicleName}".toByteArray())
file.appendBytes("\n".toByteArray())
file.appendBytes("$time---司机名称---${GlobalData.driverInfoBean?.userName ?: GlobalData.driverInfoBean?.userName}".toByteArray())
file.appendBytes("\n".toByteArray())
}
private fun getCurrentTime() : String {
return TimeUtils.millis2String(System.currentTimeMillis(), "yyyy/MM/dd HH:mm:ss.SSS")
}
class LogTask(appContext : Context, workerParams : WorkerParameters) :
Worker(appContext, workerParams) {
override fun doWork() : Result {
updateNormalLog()
return Result.success()
}
}
}