Skip to content

Commit

Permalink
fix: Switch to StateFlow in Processing
Browse files Browse the repository at this point in the history
* This should fix IndexOutOfBoundsException.
* Related: https://issuetracker.google.com/issues/300504058

Change-Id: I03a49ab732d67316600816d44ded822e660478bb
  • Loading branch information
XayahSuSuSu committed Nov 5, 2023
1 parent 1aee00c commit d1249f3
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.xayah.databackup.ui.activity.processing

import androidx.compose.animation.core.MutableTransitionState
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.lifecycle.ViewModel
import com.xayah.databackup.data.LoadingState
import com.xayah.databackup.data.ProcessingTaskFilter
Expand All @@ -13,6 +12,7 @@ import com.xayah.databackup.ui.activity.processing.components.ProcessingTask
import com.xayah.databackup.util.GlobalString
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow

class ProcessingViewModel : ViewModel() {
var listType = TypeBackupApp
Expand All @@ -27,33 +27,47 @@ class ProcessingViewModel : ViewModel() {
val progress = MutableStateFlow(0)

// 备份对象列表
val objectList = MutableStateFlow(SnapshotStateList<ProcessObjectItem>())
private val _objectList = MutableStateFlow(listOf<ProcessObjectItem>())
val objectList = _objectList.asStateFlow()

fun emitObjectList(list: List<ProcessObjectItem>) {
_objectList.value = list
}

// 任务列表
val taskList = MutableStateFlow(SnapshotStateList<ProcessingTask>())
private val _taskList = MutableStateFlow(listOf<ProcessingTask>())
val taskList = _taskList.asStateFlow()

fun emitTaskList(list: List<ProcessingTask>) {
_taskList.value = list
}

val allDone by lazy { MutableTransitionState(false) }
val isFirst = MutableStateFlow(true)
val isCancel = MutableStateFlow(false)

fun refreshTaskList() {
objectList.value.clear()
emitObjectList(listOf())
val taskList = taskList.value.toMutableList()
when (filter.value) {
ProcessingTaskFilter.None -> {
for (i in taskList.value) {
for (i in taskList) {
i.visible.value = true
}
}

ProcessingTaskFilter.Succeed -> {
for (i in taskList.value) {
for (i in taskList) {
i.visible.value = i.taskState.value == TaskState.Success
}
}
ProcessingTaskFilter.Failed -> {
for (i in taskList.value) {
for (i in taskList) {
i.visible.value = i.taskState.value != TaskState.Success
}
}
}
emitTaskList(taskList)
}

// 过滤
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,33 @@ import android.content.Context
import androidx.compose.runtime.mutableStateOf
import com.xayah.databackup.App
import com.xayah.databackup.R
import com.xayah.databackup.data.*
import com.xayah.databackup.data.AppInfoDetailRestore
import com.xayah.databackup.data.AppInfoRestore
import com.xayah.databackup.data.BackupStrategy
import com.xayah.databackup.data.CompressionType
import com.xayah.databackup.data.DataType
import com.xayah.databackup.data.LoadingState
import com.xayah.databackup.data.TaskState
import com.xayah.databackup.librootservice.RootService
import com.xayah.databackup.ui.activity.processing.ProcessingViewModel
import com.xayah.databackup.ui.activity.processing.components.ProcessObjectItem
import com.xayah.databackup.ui.activity.processing.components.ProcessingTask
import com.xayah.databackup.ui.activity.processing.components.onInfoUpdate
import com.xayah.databackup.util.*
import com.xayah.databackup.util.GlobalObject
import com.xayah.databackup.util.GlobalString
import com.xayah.databackup.util.GsonUtil
import com.xayah.databackup.util.Logcat
import com.xayah.databackup.util.Path
import com.xayah.databackup.util.command.Command
import com.xayah.databackup.util.command.Preparation
import com.xayah.databackup.util.readBackupSavePath
import com.xayah.databackup.util.readBackupStrategy
import com.xayah.databackup.util.readBackupUser
import com.xayah.databackup.util.readCompatibleMode
import com.xayah.databackup.util.readCompressionType
import com.xayah.databackup.util.readIsBackupIcon
import com.xayah.databackup.util.readIsBackupItself
import com.xayah.databackup.util.readIsResetBackupList
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
Expand All @@ -27,13 +45,11 @@ fun onBackupAppProcessing(viewModel: ProcessingViewModel, context: Context, glob
val loadingState = viewModel.loadingState
val progress = viewModel.progress
val topBarTitle = viewModel.topBarTitle
val taskList = viewModel.taskList.value
val objectList = viewModel.objectList.value.apply {
clear()
addAll(listOf(DataType.APK, DataType.USER, DataType.USER_DE, DataType.DATA, DataType.OBB, DataType.APP_MEDIA).map {
ProcessObjectItem(type = it)
})
val taskList = viewModel.taskList.value.toMutableList()
val objectList = listOf(DataType.APK, DataType.USER, DataType.USER_DE, DataType.DATA, DataType.OBB, DataType.APP_MEDIA).map {
ProcessObjectItem(type = it)
}
viewModel.emitObjectList(objectList)
val allDone = viewModel.allDone

// Check global map
Expand All @@ -59,6 +75,7 @@ fun onBackupAppProcessing(viewModel: ProcessingViewModel, context: Context, glob
objectList = listOf()
)
})
viewModel.emitTaskList(taskList)
} else {
Logcat.getInstance().actionLogAddLine(tag, "Retrying.")
}
Expand Down Expand Up @@ -108,9 +125,11 @@ fun onBackupAppProcessing(viewModel: ProcessingViewModel, context: Context, glob
subtitle.value = GlobalString.pleaseWait
}
}
viewModel.emitObjectList(objectList)

// Enter processing state
i.taskState.value = TaskState.Processing
viewModel.emitTaskList(taskList)
val appInfoBackup = globalObject.appInfoBackupMap.value[i.packageName]!!

// Scroll to processing task
Expand Down Expand Up @@ -163,18 +182,21 @@ fun onBackupAppProcessing(viewModel: ProcessingViewModel, context: Context, glob
objectList[5].visible.value = true
}
}
viewModel.emitObjectList(objectList)

// Kill the app
Preparation.killPackage(packageName)
for (j in objectList) {
if (viewModel.isCancel.value) break
if (j.visible.value) {
j.state.value = TaskState.Processing
viewModel.emitObjectList(objectList)
when (j.type) {
DataType.APK -> {
Command.compressAPK(compressionType, packageName, outPutPath, userId, appInfoBackup.detailBackup.appSize, compatibleMode)
{ type, line ->
onInfoUpdate(type, line ?: "", j)
viewModel.emitObjectList(objectList)
}.apply {
if (!this) {
isSuccess = false
Expand All @@ -193,6 +215,7 @@ fun onBackupAppProcessing(viewModel: ProcessingViewModel, context: Context, glob
Command.compress(compressionType, DataType.USER, packageName, outPutPath, Path.getUserPath(), appInfoBackup.detailBackup.userSize, compatibleMode)
{ type, line ->
onInfoUpdate(type, line ?: "", j)
viewModel.emitObjectList(objectList)
}.apply {
if (!this) {
isSuccess = false
Expand All @@ -206,6 +229,7 @@ fun onBackupAppProcessing(viewModel: ProcessingViewModel, context: Context, glob
Command.compress(compressionType, DataType.USER_DE, packageName, outPutPath, Path.getUserDePath(), appInfoBackup.detailBackup.userDeSize, compatibleMode)
{ type, line ->
onInfoUpdate(type, line ?: "", j)
viewModel.emitObjectList(objectList)
}.apply {
if (!this) {
isSuccess = false
Expand All @@ -219,6 +243,7 @@ fun onBackupAppProcessing(viewModel: ProcessingViewModel, context: Context, glob
Command.compress(compressionType, DataType.DATA, packageName, outPutPath, Path.getDataPath(), appInfoBackup.detailBackup.dataSize, compatibleMode)
{ type, line ->
onInfoUpdate(type, line ?: "", j)
viewModel.emitObjectList(objectList)
}.apply {
if (!this) {
isSuccess = false
Expand All @@ -232,6 +257,7 @@ fun onBackupAppProcessing(viewModel: ProcessingViewModel, context: Context, glob
Command.compress(compressionType, DataType.OBB, packageName, outPutPath, Path.getObbPath(), appInfoBackup.detailBackup.obbSize, compatibleMode)
{ type, line ->
onInfoUpdate(type, line ?: "", j)
viewModel.emitObjectList(objectList)
}.apply {
if (!this) {
isSuccess = false
Expand All @@ -245,6 +271,7 @@ fun onBackupAppProcessing(viewModel: ProcessingViewModel, context: Context, glob
Command.compress(compressionType, DataType.APP_MEDIA, packageName, outPutPath, Path.getAPPMediaPath(), appInfoBackup.detailBackup.mediaSize, compatibleMode)
{ type, line ->
onInfoUpdate(type, line ?: "", j)
viewModel.emitObjectList(objectList)
}.apply {
if (!this) {
isSuccess = false
Expand Down Expand Up @@ -324,6 +351,7 @@ fun onBackupAppProcessing(viewModel: ProcessingViewModel, context: Context, glob
}
this.objectList = list.toList()
}
viewModel.emitTaskList(taskList)

progress.value += 1
topBarTitle.value = "${context.getString(R.string.backing_up)}(${progress.value}/${taskList.size})"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,27 @@ import android.content.Context
import androidx.compose.runtime.mutableStateOf
import com.xayah.databackup.App
import com.xayah.databackup.R
import com.xayah.databackup.data.*
import com.xayah.databackup.data.BackupStrategy
import com.xayah.databackup.data.CompressionType
import com.xayah.databackup.data.DataType
import com.xayah.databackup.data.LoadingState
import com.xayah.databackup.data.MediaInfoDetailBase
import com.xayah.databackup.data.MediaInfoRestore
import com.xayah.databackup.data.TaskState
import com.xayah.databackup.librootservice.RootService
import com.xayah.databackup.ui.activity.processing.ProcessingViewModel
import com.xayah.databackup.ui.activity.processing.components.ProcessObjectItem
import com.xayah.databackup.ui.activity.processing.components.ProcessingTask
import com.xayah.databackup.ui.activity.processing.components.onInfoUpdate
import com.xayah.databackup.util.*
import com.xayah.databackup.util.GlobalObject
import com.xayah.databackup.util.GlobalString
import com.xayah.databackup.util.GsonUtil
import com.xayah.databackup.util.Logcat
import com.xayah.databackup.util.Path
import com.xayah.databackup.util.command.Command
import com.xayah.databackup.util.readBackupStrategy
import com.xayah.databackup.util.readCompatibleMode
import com.xayah.databackup.util.readIsResetBackupList
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
Expand All @@ -26,11 +39,9 @@ fun onBackupMediaProcessing(viewModel: ProcessingViewModel, context: Context, gl
val loadingState = viewModel.loadingState
val progress = viewModel.progress
val topBarTitle = viewModel.topBarTitle
val taskList = viewModel.taskList.value
val objectList = viewModel.objectList.value.apply {
clear()
add(ProcessObjectItem(type = DataType.DATA))
}
val taskList = viewModel.taskList.value.toMutableList()
val objectList = listOf(ProcessObjectItem(type = DataType.DATA))
viewModel.emitObjectList(objectList)
val allDone = viewModel.allDone

// Check global map
Expand All @@ -57,6 +68,7 @@ fun onBackupMediaProcessing(viewModel: ProcessingViewModel, context: Context, gl
objectList = listOf()
)
})
viewModel.emitTaskList(taskList)
} else {
Logcat.getInstance().actionLogAddLine(tag, "Retrying.")
}
Expand All @@ -83,9 +95,11 @@ fun onBackupMediaProcessing(viewModel: ProcessingViewModel, context: Context, gl
visible.value = false
subtitle.value = GlobalString.pleaseWait
}
viewModel.emitObjectList(objectList)

// Enter processing state
i.taskState.value = TaskState.Processing
viewModel.emitTaskList(taskList)
val mediaInfoBackup = globalObject.mediaInfoBackupMap.value[i.appName]!!

// Scroll to processing task
Expand All @@ -105,16 +119,19 @@ fun onBackupMediaProcessing(viewModel: ProcessingViewModel, context: Context, gl

if (i.selectData) {
objectList[0].visible.value = true
viewModel.emitObjectList(objectList)
}
for (j in objectList) {
if (viewModel.isCancel.value) break
if (j.visible.value) {
j.state.value = TaskState.Processing
viewModel.emitObjectList(objectList)
when (j.type) {
DataType.DATA -> {
Command.compress(CompressionType.TAR, DataType.MEDIA, i.appName, outPutPath, i.packageName, mediaInfoBackup.backupDetail.size, compatibleMode)
{ type, line ->
onInfoUpdate(type, line ?: "", j)
viewModel.emitObjectList(objectList)
}.apply {
if (!this) {
isSuccess = false
Expand Down
Loading

0 comments on commit d1249f3

Please sign in to comment.