title: Room Entity's data is stored correctly but is retrieved as null
body: <p><strong>What i'm trying to do</strong></p>
  <p>When my app starts, i'm using a fragment which uses an <code>AutoCompleteTextView</code> and the Places SDK to fetch a <code>Place</code> object when the user makes a selection. When that happens, i store that selected Place (as a WeatherLocation entity) through my Repository class in my Room database by calling <code>repository.storeWeatherLocation(context,placeId)</code> and then fetching the weather details again if needed.</p>
  <p><strong>What's happening</strong></p>
  <p>The <code>suspend fun storeWeatherLocationAsync</code> is calling the <code>fetchCurrentWeather()</code> &amp; <code>fetchWeeklyWeather()</code> because from what i was able to log, the <code>previousLocation</code> variable is null despite the database inspector showing that older weather location data is already present.</p>
  <p><strong>Crash details</strong></p>
  <p>My app is crashing stating that my LocationProvider's <code>getCustomLocationLat()</code> is returning null (occurs in <code>fetchCurrentWeather()</code>). The thing is that the location that the user selected is successfully stored in my Room database (checked using Database Inspector) so how is this function returning null?</p>
  <p><strong>UPDATE</strong>:</p>
  <p>After doing some more testing with the debugger and logcat, I've found out that  the <code>WeatherLocation</code> data is being saved in Room when the app is running. Once it crashes and I reopen it though, that data is once again null. What am I missing here? Am i deleting the previous data somehow? Am i not actually caching it correctly in Room?</p>
  <p>Database class:</p>
  <pre><code>@Database(
      entities = [CurrentWeatherEntry::class,WeekDayWeatherEntry::class,WeatherLocation::class],
      version = 16
  )
  abstract class ForecastDatabase : RoomDatabase() {
      abstract fun currentWeatherDao() : CurrentWeatherDao
      abstract fun weekDayWeatherDao() : WeekDayWeatherDao
      abstract fun weatherLocationDao() : WeatherLocationDao
  
      // Used to make sure that the ForecastDatabase class will be a singleton
      companion object {
          // Volatile == all of the threads will have immediate access to this property
          @Volatile private var instance:ForecastDatabase? = null
          private val LOCK = Any() // dummy object for thread monitoring
  
          operator fun invoke(context:Context) = instance ?: synchronized(LOCK) {
              // If the instance var hasn't been initialized, call buildDatabase()
              // and assign it the returned object from the function call (it)
              instance ?: buildDatabase(context).also { instance = it }
          }
  
          /**
           * Creates an instance of the ForecastDatabase class
           * using Room.databaseBuilder().
           */
          private fun buildDatabase(context: Context) =
              Room.databaseBuilder(context.applicationContext,
                  ForecastDatabase::class.java, &quot;forecast.db&quot;)
                  //.addMigrations(MIGRATION_2_3) // specify an explicit Migration Technique
                  .fallbackToDestructiveMigration()
                  .build()
      }
  }
  </code></pre>
  <p>Here's the Repository class:</p>
  <pre><code>class ForecastRepositoryImpl(
      private val currentWeatherDao: CurrentWeatherDao,
      private val weekDayWeatherDao: WeekDayWeatherDao,
      private val weatherLocationDao: WeatherLocationDao,
      private val locationProvider: LocationProvider,
      private val weatherNetworkDataSource: WeatherNetworkDataSource
  ) : ForecastRepository {
  
      init {
          weatherNetworkDataSource.apply {
              // Persist downloaded data
              downloadedCurrentWeatherData.observeForever { newCurrentWeather: CurrentWeatherResponse? -&gt;
                  persistFetchedCurrentWeather(newCurrentWeather!!)
              }
              downloadedWeeklyWeatherData.observeForever { newWeeklyWeather: WeeklyWeatherResponse? -&gt;
                  persistFetchedWeeklyWeather(newWeeklyWeather!!)
              }
          }
      }
  
      override suspend fun getCurrentWeather(): LiveData&lt;CurrentWeatherEntry&gt; {
          return withContext(Dispatchers.IO) {
              initWeatherData()
              return@withContext currentWeatherDao.getCurrentWeather()
          }
      }
  
      override suspend fun getWeekDayWeatherList(time: Long): LiveData&lt;out List&lt;WeekDayWeatherEntry&gt;&gt; {
          return withContext(Dispatchers.IO) {
              initWeatherData()
              return@withContext weekDayWeatherDao.getFutureWeather(time)
          }
      }
  
      override suspend fun getWeatherLocation(): LiveData&lt;WeatherLocation&gt; {
          return withContext(Dispatchers.IO) {
              return@withContext weatherLocationDao.getWeatherLocation()
          }
      }
  
      private suspend fun initWeatherData() {
          // retrieve the last weather location from room
          val lastWeatherLocation = weatherLocationDao.getWeatherLocation().value
  
          if (lastWeatherLocation == null ||
              locationProvider.hasLocationChanged(lastWeatherLocation)
          ) {
              fetchCurrentWeather()
              fetchWeeklyWeather()
              return
          }
  
          val lastFetchedTime = currentWeatherDao.getCurrentWeather().value?.zonedDateTime
          if (isFetchCurrentNeeded(lastFetchedTime!!))
              fetchCurrentWeather()
  
          if (isFetchWeeklyNeeded())
              fetchWeeklyWeather()
      }
  
      /**
       * Checks if the current weather data should be re-fetched.
       * @param lastFetchedTime The time at which the current weather data were last fetched
       * @return True or false respectively
       */
      private fun isFetchCurrentNeeded(lastFetchedTime: ZonedDateTime): Boolean {
          val thirtyMinutesAgo = ZonedDateTime.now().minusMinutes(30)
          return lastFetchedTime.isBefore(thirtyMinutesAgo)
      }
  
      /**
       * Fetches the Current Weather data from the WeatherNetworkDataSource.
       */
      private suspend fun fetchCurrentWeather() {
          weatherNetworkDataSource.fetchCurrentWeather(
              locationProvider.getPreferredLocationLat(),
              locationProvider.getPreferredLocationLong()
          )
      }
  
      private fun isFetchWeeklyNeeded(): Boolean {
          val todayEpochTime = LocalDate.now().toEpochDay()
          val futureWeekDayCount = weekDayWeatherDao.countFutureWeekDays(todayEpochTime)
          return futureWeekDayCount &lt; WEEKLY_FORECAST_DAYS_COUNT
      }
  
      private suspend fun fetchWeeklyWeather() {
          weatherNetworkDataSource.fetchWeeklyWeather(
              locationProvider.getPreferredLocationLat(),
              locationProvider.getPreferredLocationLong()
          )
      }
  
      override fun storeWeatherLocation(context:Context,placeId: String) {
          GlobalScope.launch(Dispatchers.IO) {
              storeWeatherLocationAsync(context,placeId)
          }
      }
  
      override suspend fun storeWeatherLocationAsync(context: Context,placeId: String) {
          var isFetchNeeded: Boolean // a flag variable
  
          // Specify the fields to return.
          val placeFields: List&lt;Place.Field&gt; =
              listOf(Place.Field.ID, Place.Field.NAME,Place.Field.LAT_LNG)
  
          // Construct a request object, passing the place ID and fields array.
          val request = FetchPlaceRequest.newInstance(placeId, placeFields)
  
          // Create the client
          val placesClient = Places.createClient(context)
  
          placesClient.fetchPlace(request).addOnSuccessListener { response -&gt;
              // Get the retrieved place object
              val place = response.place
              // Create a new WeatherLocation object using the place details
              val newWeatherLocation = WeatherLocation(place.latLng!!.latitude,
                  place.latLng!!.longitude,place.name!!,place.id!!)
  
              val previousLocation = weatherLocationDao.getWeatherLocation().value
              if(previousLocation == null || ((newWeatherLocation.latitude != previousLocation.latitude) &amp;&amp;
                  (newWeatherLocation.longitude != previousLocation.longitude))) {
                  isFetchNeeded = true
                  // Store the weatherLocation in the database
                  persistWeatherLocation(newWeatherLocation)
                  // fetch the data
                  GlobalScope.launch(Dispatchers.IO) {
                      // fetch the weather data and wait for it to finish
                      withContext(Dispatchers.Default) {
                          if (isFetchNeeded) {
                              // fetch the weather data using the new location
                              fetchCurrentWeather()
                              fetchWeeklyWeather()
                          }
                      }
                  }
              }
              Log.d(&quot;REPOSITORY&quot;,&quot;storeWeatherLocationAsync : inside task called&quot;)
          }.addOnFailureListener { exception -&gt;
              if (exception is ApiException) {
                  // Handle error with given status code.
                  Log.e(&quot;Repository&quot;, &quot;Place not found: ${exception.statusCode}&quot;)
              }
          }
      }
  
      /**
       * Caches the downloaded current weather data to the local
       * database.
       * @param fetchedCurrentWeather The most recently fetched current weather data
       */
      private fun persistFetchedCurrentWeather(fetchedCurrentWeather: CurrentWeatherResponse) {
          fetchedCurrentWeather.currentWeatherEntry.setTimezone(fetchedCurrentWeather.timezone)
          // Using a GlobalScope since a Repository class doesn't have a lifecycle
          GlobalScope.launch(Dispatchers.IO) {
              currentWeatherDao.upsert(fetchedCurrentWeather.currentWeatherEntry)
          }
      }
  
      /**
       * Caches the selected location data to the local
       * database.
       * @param fetchedLocation The most recently fetched location data
       */
      private fun persistWeatherLocation(fetchedLocation: WeatherLocation) {
          GlobalScope.launch(Dispatchers.IO) {
              weatherLocationDao.upsert(fetchedLocation)
          }
      }
  
      /**
       * Caches the downloaded weekly weather data to the local
       * database.
       * @param fetchedWeeklyWeather  The most recently fetched weekly weather data
       */
      private fun persistFetchedWeeklyWeather(fetchedWeeklyWeather: WeeklyWeatherResponse) {
  
          fun deleteOldData() {
              val time = LocalDate.now().toEpochDay()
              weekDayWeatherDao.deleteOldEntries(time)
          }
  
          GlobalScope.launch(Dispatchers.IO) {
              deleteOldData()
              val weekDayEntriesList = fetchedWeeklyWeather.weeklyWeatherContainer.weekDayEntries
              weekDayWeatherDao.insert(weekDayEntriesList)
          }
      }
  }
  </code></pre>
  <p>and here's the LocationProvider impl:</p>
  <pre><code>class LocationProviderImpl(
      private val fusedLocationProviderClient: FusedLocationProviderClient,
      context: Context,
      private val locationDao: WeatherLocationDao
  ) : PreferenceProvider(context), LocationProvider {
      private val appContext = context.applicationContext
  
      override suspend fun hasLocationChanged(lastWeatherLocation: WeatherLocation): Boolean {
          return try {
              hasDeviceLocationChanged(lastWeatherLocation)
          } catch (e:LocationPermissionNotGrantedException) {
              false
          }
      }
  
      /**
       * Makes the required checks to determine whether the device's location has
       * changed or not.
       * @param lastWeatherLocation The last known user selected location
       * @return true if the device location has changed or false otherwise
       */
      private suspend fun hasDeviceLocationChanged(lastWeatherLocation: WeatherLocation): Boolean {
          if(!isUsingDeviceLocation()) return false // we don't have location permissions or setting's disabled
  
          val currentDeviceLocation = getLastDeviceLocationAsync().await()
              ?: return false
  
          // Check if the old and new locations are far away enough that an update is needed
          val comparisonThreshold = 0.03
          return abs(currentDeviceLocation.latitude - lastWeatherLocation.latitude) &gt; comparisonThreshold
                  &amp;&amp; abs(currentDeviceLocation.longitude - lastWeatherLocation.longitude) &gt; comparisonThreshold
      }
  
      /**
       * Checks if the app has the location permission, and if that's the case
       * it will fetch the device's last saved location.
       * @return The device's last saved location as a Deferred&lt;Location?&gt;
       */
      @SuppressLint(&quot;MissingPermission&quot;)
      private fun getLastDeviceLocationAsync(): Deferred&lt;Location?&gt; {
          return if(hasLocationPermission())
              fusedLocationProviderClient.lastLocation.asDeferredAsync()
           else
              throw LocationPermissionNotGrantedException()
      }
  
      /**
       * Checks if the user has granted the location
       * permission.
       */
      private fun hasLocationPermission(): Boolean {
          return ContextCompat.checkSelfPermission(appContext,
              Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED
      }
  
      /**
       * Returns the sharedPrefs value for the USE_DEVICE_LOCATION
       * preference with a default value of &quot;true&quot;.
       */
      private fun isUsingDeviceLocation(): Boolean {
          return preferences.getBoolean(USE_DEVICE_LOCATION_KEY,false)
      }
  
      private fun getCustomLocationLat() : Double {
          val lat:Double? = locationDao.getWeatherLocation().value?.latitude
          if(lat == null) Log.d(&quot;LOCATION_PROVIDER&quot;,&quot;lat is null = $lat&quot;)
          return lat!!
      }
  
      private fun getCustomLocationLong():Double {
          return locationDao.getWeatherLocation().value!!.longitude
      }
  
      override suspend fun getPreferredLocationLat(): Double {
          if(isUsingDeviceLocation()) {
              try {
                  val deviceLocation = getLastDeviceLocationAsync().await()
                      ?: return getCustomLocationLat()
                  return deviceLocation.latitude
              } catch (e:LocationPermissionNotGrantedException) {
                  return getCustomLocationLat()
              }
          } else {
              return getCustomLocationLat()
          }
      }
  
      override suspend fun getPreferredLocationLong(): Double {
          if(isUsingDeviceLocation()) {
              try {
                  val deviceLocation = getLastDeviceLocationAsync().await()
                      ?: return getCustomLocationLong()
                  return deviceLocation.longitude
              } catch (e:LocationPermissionNotGrantedException) {
                  return getCustomLocationLong()
              }
          } else {
              return getCustomLocationLong()
          }
      }
  }
  </code></pre>