Reputation: 11
I have a queue that needs to execute tasks. There are two types of tasks: fragment work and background work. But I want to put all the work codes in the viewmodel for unified management. How should I design the framework?
I tried to use findNavController().popBackStack() to skip the UI display when the navigation is working in the background, but the viewmodel's task is also cancelled. If I change the viewmodel to activityviewmodel(), it works, but it also causes the state to not be cleared. Is there any good way to make the viewmodel become viewmodel() and make the fragment invisible?
this is fragment code
@AndroidEntryPoint
class GpsFragment : XcBaseTaskFragment<FragmentBaseStartBinding>(), TaskHandler {
val vm: XcBaseGpsViewModel by viewModels()
override fun getLayoutResId(): Int {
return R.layout.fragment_base_start
}
override fun initView() {
super.initView()
if (isBackgroundMode) {
XLog.i("initView isBackgroundMode ${isBackgroundMode}")
lifecycleScope.launcher {
withContext(Dispatchers.Main) {
vm.startGps(GlobalScope)
// GpsUtils(vm.application).startGps(GlobalScope, { !(vm.satelliteCount.value!! > 0) },
// {
// withContext(Dispatchers.Main) {
// ToastUtils.showShort("satelliteCount ${vm.satelliteCount.value}")
// }
// },{})
delay(5000)
doNextTask()
// findNavController().popBackStack()
}
}
}
}
override fun afterView() {
super.afterView()
// XLog.i("gps afterView")
if (!isBackgroundMode) {
binding.btStart.setOnClickListener {
XLog.i("startGps setOnClickListener")
lifecycleScope.launcher {
vm.startGps()
}
}
vm.satelliteCount.observe(viewLifecycleOwner) {
binding.tvStart.text = it.toString()
if (it > 0) {
doNextTask()
}
}
}
}
override fun onDestroyView() {
super.onDestroyView()
if (!isBackgroundMode) {
vm.stopGpsTest()
}
}
override suspend fun executeTaskLogic(t: XcBackgroundFragmentTask) {
// GlobalScope.launcher {
// baseTask = t
// withContext(Main) {
// GpsUtils(XcUtilsApp.instance).startGps()
// }
//// vm.startGps()
// }
}
}
this is task send code
type hereconst val ISBACKGROUNDMODE = "isBackgroundMode"
class XcBackgroundFragmentTask() : XcTask(), Parcelable {
var handler: TaskHandler? = null
open var navId: Int? = null
override suspend fun doTask() {
super.doTask()
withContext(Dispatchers.Main) {
if (XcTaskManager.getInstance().previousBackStackEntryId == null)
XcTaskManager.getInstance().previousBackStackEntryId =
XcTaskManager.getInstance().navController?.currentDestination?.id
navId?.let {
if (!isBackground()) {
// 创建 Bundle 并添加参数
val bundle = Bundle().apply {
putParcelable("task", this@XcBackgroundFragmentTask)
putBoolean(ISBACKGROUNDMODE, isBackground())
}
XLog.i("putParcelable ${this@XcBackgroundFragmentTask}")
val navOptions = NavOptions.Builder()
.setPopUpTo(XcTaskManager.getInstance().previousBackStackEntryId!!, false)
.build()
XLog.i("doTask navId $it")
XcTaskManager.getInstance().navController?.navigate(it, bundle, navOptions)
} else {
// handler?.executeTaskLogic(this@XcBackgroundFragmentTask)
val bundle = Bundle().apply {
putParcelable("task", this@XcBackgroundFragmentTask)
putBoolean(ISBACKGROUNDMODE, isBackground())
}
XcTaskManager.getInstance().navController?.navigate(it, bundle)
}
}
}
}
override suspend fun finishTask() {
if (!isBackground()) {
withContext(Dispatchers.Main) {
val isLastTask = XcTaskManager.getInstance().isLastTask()
XLog.i("isLastTask ${isLastTask}")
if (isLastTask) {
XcTaskManager.getInstance().previousBackStackEntryId?.let {
XcTaskManager.getInstance().navController?.popBackStack(
it,
false
)
XcTaskManager.getInstance().previousBackStackEntryId = null
}
}
}
}
}
fun setTaskHandler(handler: TaskHandler) {
this.handler = handler
}
fun setNavId(navId: Int) {
XLog.i("navId $navId")
this.navId = navId
}
}
interface TaskHandler {
suspend fun executeTaskLogic(task: XcBackgroundFragmentTask)
}
Upvotes: 0
Views: 55
Reputation: 1
you can try writing a singleton class that you can also hide the implementation details of gps related things in that class and inject it into the viewmodels to do the work you do in your viewmodel.
Upvotes: 0