Created
April 8, 2019 17:36
-
-
Save enriquebautista/e689dc0585ed848114e12b5fe9194ca8 to your computer and use it in GitHub Desktop.
Using CoroutineWorker
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package io.coworkerbox.data.sync | |
import android.content.Context | |
import androidx.core.content.edit | |
import androidx.work.* | |
import io.coworkerbox.BuildConfig | |
import io.coworkerbox.data.ObjectBox | |
import io.coworkerbox.data.Prefs | |
import io.coworkerbox.data.Prefs.PREF_STATE_CITY_VERSION | |
import io.coworkerbox.data.model.City | |
import io.coworkerbox.data.model.State | |
import io.objectbox.kotlin.boxFor | |
import kotlinx.coroutines.asCoroutineDispatcher | |
import okhttp3.OkHttpClient | |
import okhttp3.Request | |
import org.json.JSONException | |
import org.json.JSONObject | |
import org.json.JSONTokener | |
import timber.log.Timber | |
import java.io.IOException | |
import java.util.concurrent.Executors | |
import java.util.concurrent.TimeUnit | |
class RefreshMainDataWorker( | |
context: Context, | |
workerParams: WorkerParameters | |
) : CoroutineWorker(context, workerParams) { | |
companion object { | |
private const val TAG = "RefreshMainDataWorker" | |
private const val DEFAULT_READ_TIMEOUT = 30L // in seconds | |
private const val DEFAULT_CONNECT_TIMEOUT = 15L // in seconds | |
private const val STATES_CITIES_URL = BuildConfig.HOST.plus("Estados_Ciudades.php") | |
private const val KEY_RESPONSE = "response" | |
private const val KEY_STATUS_CODE = "statuscode" | |
private const val KEY_STATUS_MESSAGE = "statusmessage" | |
private const val KEY_RESULTSET = "resultset" | |
private const val KEY_RESULT_JSON_ARRAY = "hospitales" | |
private const val KEY_CITIES_JSONA = "ciudades" | |
private const val KEY_INACTIVE = "inactivo" | |
private const val KEY_VERSION = "version" | |
// States JSON KEYS | |
private const val KEY_STATE_ID = "id_estado" | |
private const val KEY_STATE_NAME = "nombre" | |
// Cities JSON KEYS | |
private const val KEY_CITY_ID = "id_ciudad" | |
private const val KEY_CITY_NAME = "nombre" | |
internal fun enqueueLoad() { | |
val workManager = WorkManager.getInstance() | |
workManager.enqueueUniqueWork( | |
TAG, | |
ExistingWorkPolicy.REPLACE, | |
OneTimeWorkRequestBuilder<RefreshMainDataWorker>() | |
.setConstraints(Constraints.Builder() | |
.setRequiredNetworkType(NetworkType.CONNECTED) | |
.build()) | |
.build()) | |
} | |
} | |
private val stateBox by lazy { ObjectBox.boxStore.boxFor<State>() } | |
private val cityBox by lazy { ObjectBox.boxStore.boxFor<City>() } | |
private val prefs by lazy { Prefs.getSharedPreferences(applicationContext) } | |
// Single threaded coroutine context used for all sync operations | |
private val syncSingleThreadContext by lazy { | |
Executors.newSingleThreadExecutor { target -> | |
Thread(target, "RefreshMainData") | |
}.asCoroutineDispatcher() | |
} | |
override val coroutineContext = syncSingleThreadContext | |
override suspend fun doWork(): Result { | |
return try { | |
val statesCitiesJson = fetchJsonObject(getVersionURL(STATES_CITIES_URL, PREF_STATE_CITY_VERSION)) | |
storeStatesAndCities(statesCitiesJson) | |
Result.success() | |
} catch (ex: JSONException) { | |
Timber.e(ex) | |
Result.failure() | |
} catch (ex: IOException) { | |
Timber.e(ex) | |
Result.failure() | |
} | |
} | |
@Throws(JSONException::class) | |
private fun storeStatesAndCities(response: JSONObject) { | |
val statusCode = response.getInt(KEY_STATUS_CODE) | |
val statusMessage = response.getString(KEY_STATUS_MESSAGE) | |
val versionCode = response.getLong(KEY_VERSION) | |
var jsonObject: JSONObject? | |
if(statusCode == 0) { // Ok! | |
jsonObject = response.getJSONObject(KEY_RESULTSET) | |
val dataJsonArray = jsonObject.getJSONArray(KEY_RESULT_JSON_ARRAY) | |
if(dataJsonArray != null && dataJsonArray.length() > 0) { | |
// see https://docs.objectbox.io/transactions#transaction-costs | |
val statesList = mutableListOf<State>() | |
val citiesList = mutableListOf<City>() | |
for(i in 0 until dataJsonArray.length()) { | |
jsonObject = dataJsonArray.getJSONObject(i) | |
val stateId = jsonObject.getLong(KEY_STATE_ID) | |
val stateName = jsonObject.getString(KEY_STATE_NAME) | |
val stateActive = jsonObject.getInt(KEY_INACTIVE) == 0 | |
val stateObj = State(stateId, stateName, stateActive) | |
val citiesJsonArray = jsonObject.getJSONArray(KEY_CITIES_JSONA) | |
for(j in 0 until citiesJsonArray.length()) { | |
jsonObject = citiesJsonArray.getJSONObject(j) | |
val cityId = jsonObject.getLong(KEY_CITY_ID) | |
val cityName = jsonObject.getString(KEY_CITY_NAME) | |
val cityActive = jsonObject.getInt(KEY_INACTIVE) == 0 | |
val cityObj = City(cityId, cityName, cityActive).apply { | |
state.target = stateObj | |
} | |
citiesList.add(cityObj) | |
} | |
statesList.add(stateObj) | |
} | |
stateBox.put(statesList) | |
cityBox.put(citiesList) | |
} | |
prefs.edit { putLong(PREF_STATE_CITY_VERSION, versionCode) } | |
} else { | |
Timber.e("storeStatesAndCities result FAILURE [$statusMessage]") | |
} | |
} | |
@Throws(IOException::class, JSONException::class) | |
private fun fetchJsonObject(url:String): JSONObject { | |
val client = OkHttpClient.Builder() | |
.connectTimeout(DEFAULT_CONNECT_TIMEOUT, TimeUnit.SECONDS) | |
.readTimeout(DEFAULT_READ_TIMEOUT, TimeUnit.SECONDS) | |
.build() | |
val request = Request.Builder() | |
.url(url) | |
.build() | |
val response = client.newCall(request).execute() | |
if(!response.isSuccessful) throw IOException("Unexpected code $response") | |
val json = response.body()?.string() ?: throw IOException("Response was null") | |
val tokener = JSONTokener(json) | |
var jsonObject = tokener.nextValue() as? JSONObject ?: throw JSONException("Expected JSON object.") | |
jsonObject = jsonObject.getJSONObject(KEY_RESPONSE) | |
return jsonObject | |
} | |
private fun getVersionURL(baseUrl: String, prefsKey: String): String { | |
val versionCode = prefs.getLong(prefsKey, 0L) | |
Timber.e("lastVersionCode: $versionCode") | |
return baseUrl.plus("?version=$versionCode") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment