Martin Devillers
03/15/2019, 1:27 PMobject InactiveScope
the standard library, which would be a CoroutineScope
instance with an job always in a cancelled state?
I think this would be useful in cases when we have a scope var which isn’t initialized at object creation, so we could use this object as a placeholder rather than using a null value. I’m thinking about scopes tied to Android activity states, i.e. activityCreatedScope
, activityStartedScope
, activityResumedScope
. Currently the solutions are to use lateinit
or nullable var
.streetsofboston
03/15/2019, 1:56 PMcoroutineContext
.Martin Devillers
03/15/2019, 1:58 PMstreetsofboston
03/15/2019, 2:01 PMCoroutineScope
.
But, in a similar way, an object CancelledJob : Job { ... }
could help here, that can be initially assigned to these objects’ `coroutineContext`s.Martin Devillers
03/15/2019, 2:08 PMViewModel
-like objects for tasks which are linked to the activity lifecycle, given that the ViewModel
itself is precisely designed for taks which outlive the activity lifecycle. Maybe it’s clearer if I show a current implementation:
open class CoroutineActivity : AppCompatActivity() {
private var _activityCreatedScope: CoroutineScope? = null
val activityCreatedScope: CoroutineScope
get() = _activityCreatedScope!!
private var _activityStartedScope: CoroutineScope? = null
val activityStartedScope: CoroutineScope
get() = _activityStartedScope!!
private var _activityResumedScope: CoroutineScope? = null
val activityResumedScope: CoroutineScope
get() = _activityResumedScope!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
_activityCreatedScope = MainScope()
}
override fun onStart() {
super.onStart()
_activityStartedScope = MainScope()
}
override fun onResume() {
super.onResume()
_activityResumedScope = MainScope()
}
override fun onPause() {
super.onPause()
activityResumedScope.cancel()
_activityResumedScope = null
}
override fun onStop() {
super.onStop()
activityStartedScope.cancel()
_activityStartedScope = null
}
override fun onDestroy() {
super.onDestroy()
activityCreatedScope.cancel()
_activityCreatedScope = null
}
}
This would be simpler if the `var`s for the scope could simply be initially assigned with a InactiveScope
elizarov
03/15/2019, 2:16 PMlaunch
a coroutine in a scope that is not active it does not start silently. It is hard to notice. But when you try to read a lateinit var
that was not initialized yet, then you get exception. Much better way to catch bugs.streetsofboston
03/15/2019, 2:16 PMlaunch
, async
) and never the Activity. The Activity then no longer has to worry about structured concurrency.
open class CoroutineActivity : AppCompatActivity() {
private lateinit var _vmCreatedScope: MyViewModelWithScope
private lateinit var _vmStartedScope: MyViewModelWithScope
private lateinit var _vmResumedScope: MyViewModelWithScope
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
_vmCreatedScope = MyViewModelWithScope()
}
override fun onStart() {
super.onStart()
_vmStartedScope = MyViewModelWithScope()
}
override fun onResume() {
super.onResume()
_vmResumedScope = MyViewModelWithScope()
}
override fun onPause() {
super.onPause()
vmResumedScope.cancel()
}
override fun onStop() {
super.onStop()
vmStartedScope.cancel()
}
override fun onDestroy() {
super.onDestroy()
vmCreatedScope.cancel()
}
}
And your logic is in your MyViewModelWithScope
(they could be different classes for each state, if need be; in this example, they are the same instance type) and your MyViewModelWithScope
implements CoroutineScope
Martin Devillers
03/15/2019, 2:20 PMCancelledScope
would be better, rather than inactive. This way the behavior is the same before the lifecycle reaches an “active” state and after it exits this “active” state.elizarov
03/15/2019, 2:47 PMgildor
03/16/2019, 3:49 AMobject UninitializedScope : CoroutineScope {
override val coroutineContext: CoroutineContext
get() = error("Scope is not initialized")
}