修改数据安装流程

This commit is contained in:
squallzhjch 2023-04-25 15:32:12 +08:00
parent 385e0032c2
commit 72d51c19c2
19 changed files with 289 additions and 159 deletions

View File

@ -21,7 +21,6 @@ class OMQSApplication : Application() {
Util.getInstance().init(applicationContext) Util.getInstance().init(applicationContext)
NetUtils.getInstance().init(this) NetUtils.getInstance().init(this)
TakePhotoManager.getInstance().init(this, 1) TakePhotoManager.getInstance().init(this, 1)
FileManager.initRootDir(this)
} }
private fun getKey(inputString: String): String { private fun getKey(inputString: String): String {

View File

@ -6,6 +6,7 @@ import com.navinfo.omqs.system.SystemConstant
import com.navinfo.omqs.tools.FileManager.Companion.FileDownloadStatus import com.navinfo.omqs.tools.FileManager.Companion.FileDownloadStatus
import io.realm.RealmList import io.realm.RealmList
import io.realm.RealmObject import io.realm.RealmObject
import io.realm.annotations.Ignore
import io.realm.annotations.PrimaryKey import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass import io.realm.annotations.RealmClass
@ -56,7 +57,9 @@ open class TaskBean @JvmOverloads constructor(
/** /**
* 当前下载状态 * 当前下载状态
*/ */
var status: Int = FileDownloadStatus.NONE var status: Int = FileDownloadStatus.NONE,
@Ignore
var message: String = ""
) : RealmObject() { ) : RealmObject() {
fun getDownLoadUrl(): String { fun getDownLoadUrl(): String {
return "${Constant.SERVER_ADDRESS}devcp/download?fileStr=26" return "${Constant.SERVER_ADDRESS}devcp/download?fileStr=26"

View File

@ -30,13 +30,24 @@ import kotlin.streams.toList
/** /**
* 导入omdb数据的帮助类 * 导入omdb数据的帮助类
* */ * */
class ImportOMDBHelper @AssistedInject constructor(@Assisted("context") val context: Context,@Assisted("omdbFile") val omdbFile: File) { class ImportOMDBHelper @AssistedInject constructor(
@Assisted("context") val context: Context,
@Assisted("omdbFile") val omdbFile: File
) {
@Inject @Inject
lateinit var omdbHiltFactory: OMDBDataBaseHiltFactory lateinit var omdbHiltFactory: OMDBDataBaseHiltFactory
@Inject @Inject
lateinit var gson: Gson lateinit var gson: Gson
private val database by lazy { omdbHiltFactory.obtainOmdbDataBaseHelper(context, omdbFile.absolutePath, 1).writableDatabase } private val database by lazy {
private val configFile: File = File("${Constant.DATA_PATH}/${Constant.CURRENT_USER_ID}", Constant.OMDB_CONFIG) omdbHiltFactory.obtainOmdbDataBaseHelper(
context,
omdbFile.absolutePath,
1
).writableDatabase
}
private val configFile: File =
File("${Constant.DATA_PATH}/${Constant.CURRENT_USER_ID}", Constant.OMDB_CONFIG)
/** /**
* 读取config的配置文件 * 读取config的配置文件
@ -67,8 +78,10 @@ class ImportOMDBHelper @AssistedInject constructor(@Assisted("context") val cont
} }
}.toList() }.toList()
val cursor = database.query(table, finalColumns.toTypedArray(), "1=1", val cursor = database.query(
mutableListOf<String>().toTypedArray(), null, null, null, null) table, finalColumns.toTypedArray(), "1=1",
mutableListOf<String>().toTypedArray(), null, null, null, null
)
with(cursor) { with(cursor) {
if (moveToFirst()) { if (moveToFirst()) {
while (moveToNext()) { while (moveToNext()) {
@ -76,13 +89,17 @@ class ImportOMDBHelper @AssistedInject constructor(@Assisted("context") val cont
for (columnIndex in 0 until columnCount) { for (columnIndex in 0 until columnCount) {
var columnName = getColumnName(columnIndex) var columnName = getColumnName(columnIndex)
if (columnName.startsWith("ST_AsText(")) { if (columnName.startsWith("ST_AsText(")) {
columnName = columnName.replace("ST_AsText(", "").substringBeforeLast(")") columnName = columnName.replace("ST_AsText(", "")
.substringBeforeLast(")")
} }
when (getType(columnIndex)) { when (getType(columnIndex)) {
FIELD_TYPE_NULL -> rowMap[columnName] = "" FIELD_TYPE_NULL -> rowMap[columnName] = ""
FIELD_TYPE_INTEGER -> rowMap[columnName] = getInt(columnIndex) FIELD_TYPE_INTEGER -> rowMap[columnName] =
FIELD_TYPE_FLOAT -> rowMap[columnName] = getFloat(columnIndex) getInt(columnIndex)
FIELD_TYPE_BLOB -> rowMap[columnName] = String(getBlob(columnIndex), Charsets.UTF_8) FIELD_TYPE_FLOAT -> rowMap[columnName] =
getFloat(columnIndex)
FIELD_TYPE_BLOB -> rowMap[columnName] =
String(getBlob(columnIndex), Charsets.UTF_8)
else -> rowMap[columnName] = getString(columnIndex) else -> rowMap[columnName] = getString(columnIndex)
} }
} }
@ -104,7 +121,7 @@ class ImportOMDBHelper @AssistedInject constructor(@Assisted("context") val cont
suspend fun importOmdbZipFile(omdbZipFile: File): Flow<String> = withContext(Dispatchers.IO) { suspend fun importOmdbZipFile(omdbZipFile: File): Flow<String> = withContext(Dispatchers.IO) {
val importConfig = openConfigFile() val importConfig = openConfigFile()
val unZipFolder = File(omdbZipFile.parentFile, "result") val unZipFolder = File(omdbZipFile.parentFile, "result")
flow<String> { flow {
if (unZipFolder.exists()) { if (unZipFolder.exists()) {
unZipFolder.deleteRecursively() unZipFolder.deleteRecursively()
} }
@ -123,7 +140,10 @@ class ImportOMDBHelper @AssistedInject constructor(@Assisted("context") val cont
if (list != null) { if (list != null) {
// 将list数据转换为map // 将list数据转换为map
for (line in list) { for (line in list) {
val map = gson.fromJson<Map<String, Any>>(line, object : TypeToken<MutableMap<String, Any>>() {}.type) val map = gson.fromJson<Map<String, Any>>(
line,
object : TypeToken<MutableMap<String, Any>>() {}.type
)
.toMutableMap() .toMutableMap()
map["QItable"] = currentConfig.table map["QItable"] = currentConfig.table
map["QIname"] = currentConfig.name map["QIname"] = currentConfig.name
@ -152,6 +172,7 @@ class ImportOMDBHelper @AssistedInject constructor(@Assisted("context") val cont
// 1个文件发送一次flow流 // 1个文件发送一次flow流
emit("${index + 1}/${importConfig.tables.size}") emit("${index + 1}/${importConfig.tables.size}")
} }
emit("OK")
} }
} }
@ -160,7 +181,15 @@ class ImportOMDBHelper @AssistedInject constructor(@Assisted("context") val cont
val columns = mutableListOf<String>() val columns = mutableListOf<String>()
// 查询 sqlite_master 表获取指定数据表的元数据信息 // 查询 sqlite_master 表获取指定数据表的元数据信息
val cursor = db.query("sqlite_master", arrayOf("sql"), "type='table' AND name=?", arrayOf(tableName), null, null, null) val cursor = db.query(
"sqlite_master",
arrayOf("sql"),
"type='table' AND name=?",
arrayOf(tableName),
null,
null,
null
)
// 从元数据信息中解析出列名 // 从元数据信息中解析出列名
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {

View File

@ -1,9 +1,9 @@
package com.navinfo.omqs.db package com.navinfo.omqs.db
import com.navinfo.collect.library.data.entity.QsRecordBean
import com.navinfo.omqs.bean.HadLinkDvoBean import com.navinfo.omqs.bean.HadLinkDvoBean
import com.navinfo.omqs.bean.TaskBean import com.navinfo.omqs.bean.TaskBean
import io.realm.annotations.RealmModule
@io.realm.annotations.RealmModule(classes = [TaskBean::class, HadLinkDvoBean::class]) @RealmModule(classes = [TaskBean::class, HadLinkDvoBean::class])
class MyRealmModule { class MyRealmModule {
} }

View File

@ -0,0 +1,66 @@
package com.navinfo.omqs.hilt
import android.content.Context
import com.navinfo.collect.library.map.NIMapController
import com.navinfo.omqs.db.RealmOperateHelper
import com.navinfo.omqs.db.RoomAppDatabase
import com.navinfo.omqs.http.RetrofitNetworkServiceAPI
import com.navinfo.omqs.http.offlinemapdownload.OfflineMapDownloadManager
import com.navinfo.omqs.http.taskdownload.TaskDownloadManager
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ActivityRetainedComponent
import dagger.hilt.android.qualifiers.ActivityContext
import dagger.hilt.android.scopes.ActivityRetainedScoped
@InstallIn(ActivityRetainedComponent::class)
@Module
class ActivityModule {
/**
* 注入地图控制器在activity范围内使用单例
*/
@ActivityRetainedScoped
@Provides
fun providesMapController(): NIMapController = NIMapController()
/**
* 注入离线地图下载管理在activity范围内使用单例
*/
@ActivityRetainedScoped
@Provides
fun providesOfflineMapDownloadManager(
networkServiceAPI: RetrofitNetworkServiceAPI,
roomAppDatabase: RoomAppDatabase,
mapController: NIMapController
): OfflineMapDownloadManager =
OfflineMapDownloadManager(networkServiceAPI, roomAppDatabase, mapController)
/**
* 注入任务下载
*/
@ActivityRetainedScoped
@Provides
fun providesTaskListDownloadManager(
networkServiceAPI: RetrofitNetworkServiceAPI,
importFactory: ImportOMDBHiltFactory,
): TaskDownloadManager =
TaskDownloadManager(importFactory, networkServiceAPI)
/**
* 实验失败这样创建viewmodel不会在activity销毁的时候同时销毁
* 4-14:因为没有传入activity的 owner,无法检测生命周期
*/
// @ActivityRetainedScoped
// @Provides
// fun providesMainViewModel(mapController: NIMapController): MainViewModel {
// return MainViewModel(mapController)
// }
@ActivityRetainedScoped
@Provides
fun providesRealmOperateHelper(): RealmOperateHelper {
return RealmOperateHelper()
}
}

View File

@ -15,6 +15,7 @@ import dagger.Lazy
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
import io.realm.Realm import io.realm.Realm
import kotlinx.coroutines.* import kotlinx.coroutines.*
@ -34,7 +35,7 @@ class GlobalModule {
@Singleton @Singleton
@Provides @Provides
fun provideApplication(application: Application): OMQSApplication { fun provideApplication(@ApplicationContext application: Application): OMQSApplication {
return application as OMQSApplication return application as OMQSApplication
} }

View File

@ -1,63 +1,21 @@
package com.navinfo.omqs.hilt package com.navinfo.omqs.hilt
import android.content.Context
import com.navinfo.collect.library.map.NIMapController import com.navinfo.collect.library.map.NIMapController
import com.navinfo.omqs.db.RealmOperateHelper
import com.navinfo.omqs.db.RoomAppDatabase
import com.navinfo.omqs.http.RetrofitNetworkServiceAPI
import com.navinfo.omqs.http.offlinemapdownload.OfflineMapDownloadManager
import com.navinfo.omqs.http.taskdownload.TaskDownloadManager
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.android.components.ActivityRetainedComponent import dagger.hilt.android.components.ActivityComponent
import dagger.hilt.android.scopes.ActivityRetainedScoped import dagger.hilt.android.qualifiers.ActivityContext
import dagger.hilt.android.scopes.ActivityScoped
@InstallIn(ActivityRetainedComponent::class) @InstallIn(ActivityComponent::class)
@Module @Module
class MainActivityModule { class MainActivityModule {
/** /**
* 注入地图控制器在activity范围内使用单例 * 注入地图控制器在activity范围内使用单例
*/ */
@ActivityRetainedScoped @ActivityScoped
@Provides @Provides
fun providesMapController(): NIMapController = NIMapController() fun providesContext(@ActivityContext context: Context): Context = context
/**
* 注入离线地图下载管理在activity范围内使用单例
*/
@ActivityRetainedScoped
@Provides
fun providesOfflineMapDownloadManager(
networkServiceAPI: RetrofitNetworkServiceAPI,
roomAppDatabase: RoomAppDatabase,
mapController: NIMapController
): OfflineMapDownloadManager =
OfflineMapDownloadManager(networkServiceAPI, roomAppDatabase, mapController)
/**
* 注入任务下载
*/
@ActivityRetainedScoped
@Provides
fun providesTaskListDownloadManager(
networkServiceAPI: RetrofitNetworkServiceAPI,
): TaskDownloadManager =
TaskDownloadManager(networkServiceAPI)
/**
* 实验失败这样创建viewmodel不会在activity销毁的时候同时销毁
* 4-14:因为没有传入activity的 owner,无法检测生命周期
*/
// @ActivityRetainedScoped
// @Provides
// fun providesMainViewModel(mapController: NIMapController): MainViewModel {
// return MainViewModel(mapController)
// }
@ActivityRetainedScoped
@Provides
fun providesRealmOperateHelper(): RealmOperateHelper {
return RealmOperateHelper()
}
} }

View File

@ -0,0 +1,7 @@
//package com.navinfo.omqs.hilt
//
//import javax.inject.Qualifier
//
//@Qualifier
//@Retention(AnnotationRetention.RUNTIME)
//annotation class ActivityContext

View File

@ -1,23 +1,32 @@
package com.navinfo.omqs.http.taskdownload package com.navinfo.omqs.http.taskdownload
import android.content.Context
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import com.navinfo.omqs.bean.TaskBean import com.navinfo.omqs.bean.TaskBean
import com.navinfo.omqs.hilt.ImportOMDBHiltFactory
import com.navinfo.omqs.hilt.OMDBDataBaseHiltFactory
import com.navinfo.omqs.http.RetrofitNetworkServiceAPI import com.navinfo.omqs.http.RetrofitNetworkServiceAPI
import dagger.hilt.android.qualifiers.ActivityContext
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import javax.inject.Inject
/** /**
* 管理任务数据下载 * 管理任务数据下载
*/ */
class TaskDownloadManager( class TaskDownloadManager constructor(
val importFactory: ImportOMDBHiltFactory,
val netApi: RetrofitNetworkServiceAPI, val netApi: RetrofitNetworkServiceAPI,
) { ) {
lateinit var context: Context
/** /**
* 最多同时下载数量 * 最多同时下载数量
*/ */
private val MAX_SCOPE = 3 private val MAX_SCOPE = 1
/** /**
* 存储有哪些城市需要下载的队列 * 存储有哪些城市需要下载的队列
@ -33,6 +42,9 @@ class TaskDownloadManager(
ConcurrentHashMap<Int, TaskDownloadScope>() ConcurrentHashMap<Int, TaskDownloadScope>()
} }
fun init(context: Context) {
this.context = context
}
/** /**
* 启动下载任务 * 启动下载任务

View File

@ -1,23 +1,34 @@
package com.navinfo.omqs.http.taskdownload package com.navinfo.omqs.http.taskdownload
import android.content.Context
import android.util.Log import android.util.Log
import androidx.core.content.ContentProviderCompat.requireContext
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import com.navinfo.omqs.Constant import com.navinfo.omqs.Constant
import com.navinfo.omqs.bean.TaskBean import com.navinfo.omqs.bean.TaskBean
import com.navinfo.omqs.db.ImportOMDBHelper
import com.navinfo.omqs.hilt.ImportOMDBHiltFactory
import com.navinfo.omqs.tools.FileManager
import com.navinfo.omqs.tools.FileManager.Companion.FileDownloadStatus import com.navinfo.omqs.tools.FileManager.Companion.FileDownloadStatus
import io.realm.Realm
import kotlinx.coroutines.* import kotlinx.coroutines.*
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
import java.io.InputStream import java.io.InputStream
import java.io.RandomAccessFile import java.io.RandomAccessFile
import javax.inject.Inject
class TaskDownloadScope( class TaskDownloadScope(
private val downloadManager: TaskDownloadManager, private val downloadManager: TaskDownloadManager,
val taskBean: TaskBean, val taskBean: TaskBean,
) : ) :
CoroutineScope by CoroutineScope(Dispatchers.IO + CoroutineName("OfflineMapDownLoad")) { CoroutineScope by CoroutineScope(Dispatchers.IO + CoroutineName("OfflineMapDownLoad")) {
@Inject
lateinit var importOMDBHiltFactory: ImportOMDBHiltFactory
/** /**
*下载任务用来取消的 *下载任务用来取消的
*/ */
@ -59,7 +70,12 @@ class TaskDownloadScope(
*/ */
fun launch() { fun launch() {
downloadJob = launch() { downloadJob = launch() {
FileManager.checkOMDBFileInfo(taskBean)
if (taskBean.status == FileDownloadStatus.IMPORT) {
importData()
} else {
download() download()
}
downloadManager.launchNext(taskBean.id) downloadManager.launchNext(taskBean.id)
} }
} }
@ -76,14 +92,17 @@ class TaskDownloadScope(
* 更新任务 * 更新任务
* @param status [OfflineMapCityBean.Status] * @param status [OfflineMapCityBean.Status]
*/ */
private fun change(status: Int) { private fun change(status: Int, message: String = "") {
if (taskBean.status != status || status == FileDownloadStatus.LOADING) { if (taskBean.status != status || status == FileDownloadStatus.LOADING || status == FileDownloadStatus.IMPORTING) {
taskBean.status = status taskBean.status = status
taskBean.message = message
downloadData.postValue(taskBean) downloadData.postValue(taskBean)
launch(Dispatchers.IO) { launch {
// downloadManager.roomDatabase.getOfflineMapDao().update(taskBean) val realm = Realm.getDefaultInstance()
realm.executeTransaction {
it.copyToRealmOrUpdate(taskBean)
}
} }
} }
} }
@ -96,36 +115,75 @@ class TaskDownloadScope(
downloadData.observe(owner, ob) downloadData.observe(owner, ob)
} }
/**
* 导入数据
*/
private suspend fun importData(file: File? = null) {
try {
Log.e("jingo", "importData SSS")
change(FileDownloadStatus.IMPORTING)
var fileNew = file
?: File("${Constant.DOWNLOAD_PATH}${taskBean.evaluationTaskName}_${taskBean.dataVersion}.zip")
val importOMDBHelper: ImportOMDBHelper =
downloadManager.importFactory.obtainImportOMDBHelper(
downloadManager.context,
fileNew
)
importOMDBHelper.importOmdbZipFile(importOMDBHelper.omdbFile).collect {
Log.e("jingo", "数据安装 $it")
if (it == "OK") {
change(FileDownloadStatus.DONE)
} else {
change(FileDownloadStatus.IMPORTING, it)
}
}
} catch (e: Exception) {
Log.e("jingo", "数据安装失败 ${e.toString()}")
change(FileDownloadStatus.ERROR)
}
Log.e("jingo", "importData EEE")
}
/** /**
* 下载文件 * 下载文件
*/ */
private suspend fun download() { private suspend fun download() {
//如果文件下载安装已经完毕
if (taskBean.status == FileDownloadStatus.DONE) {
return
}
var inputStream: InputStream? = null var inputStream: InputStream? = null
var randomAccessFile: RandomAccessFile? = null var randomAccessFile: RandomAccessFile? = null
try { try {
//创建离线地图 下载文件夹,.map文件夹的下一级 //创建离线地图 下载文件夹,.map文件夹的下一级
val fileDir = File("${Constant.DOWNLOAD_PATH}download") val fileDir = File("${Constant.DOWNLOAD_PATH}")
if (!fileDir.exists()) { if (!fileDir.exists()) {
fileDir.mkdirs() fileDir.mkdirs()
} }
val fileTemp = val fileTemp =
File("${Constant.DOWNLOAD_PATH}${taskBean.id}_${taskBean.dataVersion}") File("${Constant.DOWNLOAD_PATH}${taskBean.evaluationTaskName}_${taskBean.dataVersion}.zip")
val startPosition = taskBean.currentSize val startPosition = taskBean.currentSize
//验证断点有效性
if (startPosition < 0) throw IOException("jingo Start position less than zero") if (fileTemp.length() > 0 && taskBean.fileSize > 0 && fileTemp.length() == taskBean.fileSize) {
importData(fileTemp)
return
}
val response = downloadManager.netApi.retrofitDownLoadFile( val response = downloadManager.netApi.retrofitDownLoadFile(
start = "bytes=$startPosition-", start = "bytes=$startPosition-",
url = taskBean.getDownLoadUrl() url = taskBean.getDownLoadUrl()
) )
val responseBody = response.body() val responseBody = response.body()
change(FileDownloadStatus.LOADING)
responseBody ?: throw IOException("jingo ResponseBody is null")
responseBody ?: throw IOException("jingo ResponseBody is null")
if (startPosition == 0L) { if (startPosition == 0L) {
taskBean.fileSize = responseBody.contentLength() taskBean.fileSize = responseBody.contentLength()
Log.e("jingo", "当前文件大小 ${taskBean.fileSize}")
} }
change(FileDownloadStatus.LOADING)
//写入文件 //写入文件
randomAccessFile = RandomAccessFile(fileTemp, "rwd") randomAccessFile = RandomAccessFile(fileTemp, "rwd")
randomAccessFile.seek(startPosition) randomAccessFile.seek(startPosition)
@ -146,17 +204,14 @@ class TaskDownloadScope(
} }
} }
Log.e("jingo", "文件下载完成 ${taskBean.currentSize} == ${taskBean.fileSize}")
if (taskBean.currentSize == taskBean.fileSize) { if (taskBean.currentSize == taskBean.fileSize) {
val res = importData(fileTemp)
fileTemp.renameTo(File("${Constant.DOWNLOAD_PATH}${taskBean.evaluationTaskName}.zip"))
Log.e("jingo", "文件下载完成 修改文件 $res")
change(FileDownloadStatus.DONE)
} else { } else {
change(FileDownloadStatus.PAUSE) change(FileDownloadStatus.PAUSE)
} }
} catch (e: Throwable) { } catch (e: Throwable) {
change(FileDownloadStatus.ERROR) change(FileDownloadStatus.ERROR)
Log.e("jingo","数据下载出错 ${e.message}")
} finally { } finally {
inputStream?.close() inputStream?.close()
randomAccessFile?.close() randomAccessFile?.close()

View File

@ -16,8 +16,10 @@ class FileManager {
const val LOADING = 2 //下载中 const val LOADING = 2 //下载中
const val PAUSE = 3 //暂停 const val PAUSE = 3 //暂停
const val ERROR = 4 //错误 const val ERROR = 4 //错误
const val DONE = 5 //完成 const val IMPORT = 5 //安装
const val UPDATE = 6 //有新版本要更新 const val IMPORTING = 6 //安装中
const val UPDATE = 7 //有新版本要更新
const val DONE = 8 //完成
} }
//初始化数据文件夹 //初始化数据文件夹
@ -109,60 +111,28 @@ class FileManager {
* 检查离线地图文件 * 检查离线地图文件
*/ */
suspend fun checkOMDBFileInfo(taskBean: TaskBean) { suspend fun checkOMDBFileInfo(taskBean: TaskBean) {
if (taskBean.status == FileDownloadStatus.DONE)
return
//访问离线地图文件夹 //访问离线地图文件夹
val fileDir = File("${Constant.DOWNLOAD_PATH}") val fileDir = File("${Constant.DOWNLOAD_PATH}")
//如果连本地文件夹还没有,就不用修改任何数据了 //如果连本地文件夹还没有,就不用修改任何数据了
if (!fileDir.exists()) { if (!fileDir.exists()) {
return return
} }
//访问离线地图临时下载文件夹
val fileTempDir = File(Constant.DOWNLOAD_PATH)
//是否有一份.map文件了
var mapFile: File? = null
//文件夹里文件挨个访问 //文件夹里文件挨个访问
for (item in fileDir.listFiles()) { for (item in fileDir.listFiles()) {
//先找到对应的省市文件例如540000_西藏自治区_20230401195018.map",以id开头 //先找到对应的省市文件例如540000_西藏自治区_20230401195018.map",以id开头
if (item.isFile && item.name.startsWith("${taskBean.id}_")) { if (item.isFile && item.name == "${taskBean.evaluationTaskName}_${taskBean.dataVersion}.zip") {
//如果本地文件与从网络获取到版本号一致,表示这个文件已经下载完毕,不用处理了
if (item.name == "${taskBean.id}_${taskBean.dataVersion}") {
taskBean.status = FileDownloadStatus.DONE
return
}
//文件存在,版本号不对应,留给下面流程处理
mapFile = item
break
}
}
//临时下载文件夹
if (fileTempDir.exists()) {
for (item in fileTempDir.listFiles()) {
//先找到对应的省市文件例如540000_20230401195018",以id开头
if (item.isFile && item.name.startsWith("${taskBean.id}_")) {
//如果本地文件与从网络获取到版本号一致,表示这个文件已经在下载列表中
if (item.name == "${taskBean.id}_${taskBean.dataVersion}") {
//如果这个临时文件的大小和下载大小是一致的,说明已经下载完了,但是在下载环节没有更名移动成功,需要重命名和移动文件夹
if (item.length() == taskBean.fileSize) {
//移动更名文件后删除旧数据,修改状态
if (item.renameTo(File("${Constant.OFFLINE_MAP_PATH}${taskBean.evaluationTaskName}.zip"))) {
//删除旧版本数据
mapFile?.delete()
taskBean.status = FileDownloadStatus.DONE
return
}
} else { // 临时文件大小和目标不一致,说明下载了一半
taskBean.status = FileDownloadStatus.PAUSE
taskBean.currentSize = item.length() taskBean.currentSize = item.length()
if (taskBean.fileSize > 0 && taskBean.fileSize == item.length()) {
taskBean.status = FileDownloadStatus.IMPORT
} else {
taskBean.status = FileDownloadStatus.PAUSE
}
return return
} }
} else { //虽然省市id开头一致但是版本号不一致说明之前版本下载了一部分现在要更新了原来下载的文件直接删除
taskBean.status = FileDownloadStatus.UPDATE
item.delete()
return
}
break
}
}
} }
taskBean.status = FileDownloadStatus.NONE
} }
} }
} }

View File

@ -10,6 +10,7 @@ import androidx.lifecycle.viewModelScope
import com.blankj.utilcode.util.ResourceUtils import com.blankj.utilcode.util.ResourceUtils
import com.navinfo.omqs.Constant import com.navinfo.omqs.Constant
import com.navinfo.omqs.bean.LoginUserBean import com.navinfo.omqs.bean.LoginUserBean
import com.navinfo.omqs.db.MyRealmModule
import com.navinfo.omqs.db.RoomAppDatabase import com.navinfo.omqs.db.RoomAppDatabase
import com.navinfo.omqs.http.NetResult import com.navinfo.omqs.http.NetResult
import com.navinfo.omqs.http.NetworkService import com.navinfo.omqs.http.NetworkService
@ -168,7 +169,7 @@ class LoginViewModel @Inject constructor(
.directory(userFolder) .directory(userFolder)
.name("OMQS.realm") .name("OMQS.realm")
.encryptionKey(password) .encryptionKey(password)
// .modules(Realm.getDefaultModule(), MyRealmModule()) .modules(Realm.getDefaultModule(), MyRealmModule())
.schemaVersion(1) .schemaVersion(1)
.build() .build()
Realm.setDefaultConfiguration(config) Realm.setDefaultConfiguration(config)

View File

@ -1,6 +1,7 @@
package com.navinfo.omqs.ui.activity.map package com.navinfo.omqs.ui.activity.map
import android.os.Bundle import android.os.Bundle
import android.view.View
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.databinding.DataBindingUtil import androidx.databinding.DataBindingUtil
@ -14,6 +15,7 @@ import com.navinfo.omqs.Constant
import com.navinfo.omqs.R import com.navinfo.omqs.R
import com.navinfo.omqs.databinding.ActivityMainBinding import com.navinfo.omqs.databinding.ActivityMainBinding
import com.navinfo.omqs.http.offlinemapdownload.OfflineMapDownloadManager import com.navinfo.omqs.http.offlinemapdownload.OfflineMapDownloadManager
import com.navinfo.omqs.http.taskdownload.TaskDownloadManager
import com.navinfo.omqs.system.SystemConstant import com.navinfo.omqs.system.SystemConstant
import com.navinfo.omqs.ui.activity.BaseActivity import com.navinfo.omqs.ui.activity.BaseActivity
import com.navinfo.omqs.ui.fragment.evaluationresult.EvaluationResultFragment import com.navinfo.omqs.ui.fragment.evaluationresult.EvaluationResultFragment
@ -37,10 +39,10 @@ class MainActivity : BaseActivity() {
@Inject @Inject
lateinit var offlineMapDownloadManager: OfflineMapDownloadManager lateinit var offlineMapDownloadManager: OfflineMapDownloadManager
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
WindowCompat.setDecorFitsSystemWindows(window, false) WindowCompat.setDecorFitsSystemWindows(window, false)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main) binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
//初始化地图 //初始化地图
mapController.init( mapController.init(

View File

@ -3,38 +3,24 @@ package com.navinfo.omqs.ui.fragment.personalcenter
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import com.blankj.utilcode.util.UriUtils import com.blankj.utilcode.util.UriUtils
import com.github.k1rakishou.fsaf.FileChooser import com.github.k1rakishou.fsaf.FileChooser
import com.github.k1rakishou.fsaf.callback.FSAFActivityCallbacks import com.github.k1rakishou.fsaf.callback.FSAFActivityCallbacks
import com.github.k1rakishou.fsaf.callback.FileChooserCallback import com.github.k1rakishou.fsaf.callback.FileChooserCallback
import com.navinfo.collect.library.data.RealmUtils
import com.navinfo.collect.library.data.entity.OMDBEntity
import com.navinfo.collect.library.map.NIMapController import com.navinfo.collect.library.map.NIMapController
import com.navinfo.omqs.R import com.navinfo.omqs.R
import com.navinfo.omqs.databinding.FragmentPersonalCenterBinding import com.navinfo.omqs.databinding.FragmentPersonalCenterBinding
import com.navinfo.omqs.db.ImportOMDBHelper import com.navinfo.omqs.db.ImportOMDBHelper
import com.navinfo.omqs.hilt.ImportOMDBHiltFactory import com.navinfo.omqs.hilt.ImportOMDBHiltFactory
import com.navinfo.omqs.tools.CoroutineUtils import com.navinfo.omqs.tools.CoroutineUtils
import com.navinfo.omqs.ui.activity.BaseActivity
import com.navinfo.omqs.ui.fragment.BaseFragment import com.navinfo.omqs.ui.fragment.BaseFragment
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import io.realm.Realm
import io.realm.RealmDictionary
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.oscim.core.GeoPoint import org.oscim.core.GeoPoint
import java.io.File
import java.util.UUID
import javax.inject.Inject import javax.inject.Inject
/** /**

View File

@ -13,6 +13,8 @@ import com.navinfo.omqs.http.taskdownload.TaskDownloadManager
import com.navinfo.omqs.tools.FileManager.Companion.FileDownloadStatus import com.navinfo.omqs.tools.FileManager.Companion.FileDownloadStatus
import com.navinfo.omqs.ui.other.BaseRecyclerViewAdapter import com.navinfo.omqs.ui.other.BaseRecyclerViewAdapter
import com.navinfo.omqs.ui.other.BaseViewHolder import com.navinfo.omqs.ui.other.BaseViewHolder
import java.io.File
import javax.inject.Inject
/** /**
* 离线地图城市列表 RecyclerView 适配器 * 离线地图城市列表 RecyclerView 适配器
@ -31,7 +33,7 @@ class TaskListAdapter(
if (it.tag != null) { if (it.tag != null) {
val taskBean = data[it.tag as Int] val taskBean = data[it.tag as Int]
when (taskBean.status) { when (taskBean.status) {
FileDownloadStatus.NONE, FileDownloadStatus.UPDATE, FileDownloadStatus.PAUSE, FileDownloadStatus.ERROR -> { FileDownloadStatus.NONE, FileDownloadStatus.UPDATE, FileDownloadStatus.PAUSE, FileDownloadStatus.IMPORT, FileDownloadStatus.ERROR -> {
Log.e("jingo", "开始下载 ${taskBean.status}") Log.e("jingo", "开始下载 ${taskBean.status}")
downloadManager.start(taskBean.id) downloadManager.start(taskBean.id)
} }
@ -125,6 +127,29 @@ class TaskListAdapter(
View.INVISIBLE View.INVISIBLE
binding.taskDownloadBtn.text = "更新" binding.taskDownloadBtn.text = "更新"
} }
FileDownloadStatus.IMPORTING -> {
if (binding.taskProgress.visibility != View.VISIBLE) binding.taskProgress.visibility =
View.VISIBLE
binding.taskDownloadBtn.text = "安装中"
val split = taskBean.message.split("/")
if (split.size == 2) {
try {
val index = split[0].toInt()
val count = split[1].toInt()
binding.taskProgress.progress =
index * 100 / count
} catch (e: Exception) {
Log.e("jingo", "更新进度条 $e")
}
} else {
binding.taskProgress.progress = 0
}
}
FileDownloadStatus.IMPORT -> {
if (binding.taskProgress.visibility != View.VISIBLE) binding.taskProgress.visibility =
View.INVISIBLE
binding.taskDownloadBtn.text = "安装"
}
} }
} }

View File

@ -30,6 +30,7 @@ class TaskListFragment : BaseFragment(){
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View { ): View {
downloadManager.init(requireContext())
_binding = FragmentTaskListBinding.inflate(inflater, container, false) _binding = FragmentTaskListBinding.inflate(inflater, container, false)
return binding.root return binding.root

View File

@ -28,11 +28,27 @@ class TaskListViewModel @Inject constructor(
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
val realm = Realm.getDefaultInstance() val realm = Realm.getDefaultInstance()
Log.e("jingo", "realm hashCOde ${realm.hashCode()}") Log.e("jingo", "realm hashCOde ${realm.hashCode()}")
var taskList: List<TaskBean> = mutableListOf()
when (val result = networkService.getTaskList("02911")) { when (val result = networkService.getTaskList("02911")) {
is NetResult.Success -> { is NetResult.Success -> {
if (result.data != null) { if (result.data != null) {
realm.executeTransaction { realm.executeTransaction {
realm.copyToRealmOrUpdate(result.data.obj) result.data.obj?.let { list ->
for (task in list) {
val item = realm.where(TaskBean::class.java).equalTo(
"id", task.id
).findFirst()
if (item != null) {
task.fileSize = item.fileSize
Log.e("jingo", "当前文件大小 ${task.fileSize}")
task.status = item.status
task.currentSize = item.currentSize
}
realm.copyToRealmOrUpdate(task)
}
}
val objects = realm.where(TaskBean::class.java).findAll()
taskList = realm.copyFromRealm(objects)
} }
} }
} }
@ -51,8 +67,7 @@ class TaskListViewModel @Inject constructor(
is NetResult.Loading -> {} is NetResult.Loading -> {}
else -> {} else -> {}
} }
val objects = realm.where(TaskBean::class.java).findAll()
val taskList = realm.copyFromRealm(objects)
for (item in taskList) { for (item in taskList) {
FileManager.checkOMDBFileInfo(item) FileManager.checkOMDBFileInfo(item)
} }

View File

@ -8,6 +8,7 @@
android:paddingLeft="10dp" android:paddingLeft="10dp"
android:paddingTop="5dp" android:paddingTop="5dp"
android:paddingRight="10dp" android:paddingRight="10dp"
android:paddingBottom="5dp"
tools:context="com.navinfo.omqs.ui.fragment.tasklist.TaskListAdapter"> tools:context="com.navinfo.omqs.ui.fragment.tasklist.TaskListAdapter">
<TextView <TextView

View File

@ -4,7 +4,6 @@ import com.navinfo.collect.library.utils.GeometryToolsKt
import io.realm.RealmObject import io.realm.RealmObject
import io.realm.RealmSet import io.realm.RealmSet
import io.realm.annotations.PrimaryKey import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
/** /**