title: NetworkBoundResource with Kotlin coroutines
body: <p>Do you have any ideas how to implement repository pattern with <a href="https://github.com/android/architecture-components-samples/blob/master/GithubBrowserSample/app/src/main/java/com/android/example/github/repository/NetworkBoundResource.kt" rel="noreferrer"><strong>NetworkBoundResource</strong></a> and Kotlin coroutines? I know we can launch a coroutine withing a GlobalScope, but it may lead to coroutine leak. I would like to pass a <strong>viewModelScope</strong> as a parameter, but it is a bit tricky, when it comes to implementation (because my repository doesn't know a CoroutineScope of any ViewModel).</p>
  
  <pre><code>abstract class NetworkBoundResource&lt;ResultType, RequestType&gt;
  @MainThread constructor(
      private val coroutineScope: CoroutineScope
  ) {
  
      private val result = MediatorLiveData&lt;Resource&lt;ResultType&gt;&gt;()
  
      init {
          result.value = Resource.loading(null)
          @Suppress("LeakingThis")
          val dbSource = loadFromDb()
          result.addSource(dbSource) { data -&gt;
              result.removeSource(dbSource)
              if (shouldFetch(data)) {
                  fetchFromNetwork(dbSource)
              } else {
                  result.addSource(dbSource) { newData -&gt;
                      setValue(Resource.success(newData))
                  }
              }
          }
      }
  
      @MainThread
      private fun setValue(newValue: Resource&lt;ResultType&gt;) {
          if (result.value != newValue) {
              result.value = newValue
          }
      }
  
      private fun fetchFromNetwork(dbSource: LiveData&lt;ResultType&gt;) {
          val apiResponse = createCall()
          result.addSource(dbSource) { newData -&gt;
              setValue(Resource.loading(newData))
          }
          result.addSource(apiResponse) { response -&gt;
              result.removeSource(apiResponse)
              result.removeSource(dbSource)
              when (response) {
                  is ApiSuccessResponse -&gt; {
                      coroutineScope.launch(Dispatchers.IO) {
                          saveCallResult(processResponse(response))
  
                          withContext(Dispatchers.Main) {
                              result.addSource(loadFromDb()) { newData -&gt;
                                  setValue(Resource.success(newData))
                              }
                          }
                      }
                  }
  
                  is ApiEmptyResponse -&gt; {
                      coroutineScope.launch(Dispatchers.Main) {
                          result.addSource(loadFromDb()) { newData -&gt;
                              setValue(Resource.success(newData))
                          }
                      }
                  }
  
                  is ApiErrorResponse -&gt; {
                      onFetchFailed()
                      result.addSource(dbSource) { newData -&gt;
                          setValue(Resource.error(response.errorMessage, newData))
                      }
                  }
              }
          }
      }
  }
  </code></pre>