title: Is the Kotlin Structured Concurrency [coroutine] model scoped to UI suitable for DB writes?
body: <p><em>I'm specifically concerned about inserting user initiated data into the local database.</em></p>
  
  <p>The following pattern is prevalent in examples (including from official sources, e.g. JetBrains, Google/Android) for using Kotlin coroutines in conjunction with [Android Architecture Components] ViewModels.</p>
  
  <pre><code>class CoroutineScopedViewModel : ViewModel(), CoroutineScope {
      private val _job = Job()
      override val coroutineContext: CoroutineContext
          get() = Dispatchers.Main + _job
  
      override fun onCleared() {
          super.onCleared()
          _job.cancel()
      }
  
      fun thisIsCalledFromTheUI() = launch {
          /* do some UI stuff on the main thread */
          withContext(Dispatchers.IO) {
              try {
                  /* do some IO, e.g. inserting into DB */
              } catch (error: IOException) {
                  /* do some exception handling */
              }
          }
      }
  }
  </code></pre>
  
  <p>It's my understanding of the <a href="https://github.com/Kotlin/kotlinx.coroutines/blob/master/ui/coroutines-guide-ui.md#structured-concurrency-lifecycle-and-coroutine-parent-child-hierarchy" rel="nofollow noreferrer">documentation</a> that in the above example the coroutines started in the UI context (defined through  <code>coroutineContext</code>) will be cancelled when the <code>ViewModel</code> is destroyed, but that the code in the <code>withContext(Dispatchers.IO)</code> block will get to run to completion.</p>
  
  <p>But, before I go about refactoring my project from the (pre-1.0.0) globally scoped (launch/async) coroutine model, I feel I need to just have some things clarified: </p>
  
  <p>Is my reading of the documentation correct? Or, will destruction of the viewmodel before the  <code>withContext(Dispatchers.IO)</code> block runs to completion  trigger cancellation of that job too? I.e. can this model be used for inserting data into my DB, or could some strange timing issue arise where the user hits back or otherwise causes the ViewModel owner to close that ends up losing the data?</p>
  
  <p>I don't want to inadvertently introduce a timing bug because I misunderstood something and therefor converted my code to a model similar to the one shown above.</p>
  
  <h3>EDIT:</h3>
  
  <p>So, I decided to do a little test, and it seems to me that all those examples using this model to write to the database may have a fundamental bug.</p>
  
  <p>Modifying the code to log what happens, as such:</p>
  
  <pre><code>class ChildViewModel : ViewModel(), CoroutineScope {
      private val _job = Job()
      override val coroutineContext: CoroutineContext
          get() = Dispatchers.Main + _job
  
      override fun onCleared() {
          super.onCleared()
          Log.d("onCleared", "Start")
          _job.cancel()
          Log.d("onCleared", "End")
      }
  
      fun thisIsCalledFromTheUI() = launch {
          Log.d("thisIsCalledFromTheUI", "Start")
          GlobalScope.launch(Dispatchers.IO) {
              Log.d("GlobalScope", "Start")
              delay(15000)
              Log.d("GlobalScope", "End")
          }
          withContext(Dispatchers.IO) {
              Log.d("withContext", "Start")
              delay(10000)
              Log.d("withContext", "End")
          }
          Log.d("thisIsCalledFromTheUI", "End")
      }
  }
  </code></pre>
  
  <p>Results in this, if you let it run to completion:</p>
  
  <pre><code>D/thisIsCalledFromTheUI: Start
  D/GlobalScope: Start
  D/withContext: Start
  D/withContext: End
  D/thisIsCalledFromTheUI: End
  D/GlobalScope: End
  </code></pre>
  
  <p>But, if you close the Fragment/Activity (not the app) before <code>withContext</code> ends, you get this:</p>
  
  <pre><code>D/thisIsCalledFromTheUI: Start
  D/GlobalScope: Start
  D/withContext: Start
  D/GlobalScope: End
  </code></pre>
  
  <p>Which indicates, to me at least, that you cannot use this to write non-transient data to the DB.</p>