Skip to content

Commit

Permalink
clean up coroutines, data in page change
Browse files Browse the repository at this point in the history
  • Loading branch information
cloudbank committed May 14, 2020
1 parent 30bb462 commit 682c8ed
Show file tree
Hide file tree
Showing 9 changed files with 42 additions and 39 deletions.
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ dependencies {
implementation deps.lifecycle.runtime
implementation deps.paging_ktx
implementation deps.kotlin.stdlib
implementation deps.kotlin.reflect
implementation deps.retrofit.runtime
implementation deps.retrofit.gson
implementation deps.retrofit.scalars
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ import com.droidteahouse.coronaTracker.vo.Area
@Dao
interface CoronaTrackerDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(areas: List<Area>)
suspend fun insert(areas: List<Area>)

@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertWorld(apiResponse: ApiResponse)
suspend fun insertWorld(apiResponse: ApiResponse)

@Transaction
suspend fun updateAll(apiResponse: ApiResponse): Int {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ import kotlinx.coroutines.CoroutineScope


interface CoronaTrackerRepository {
fun areasOfCoronaTracker(pageSize: Int, ioScope: CoroutineScope, mainScope: CoroutineScope): Listing<Area>
suspend fun areasOfCoronaTracker(pageSize: Int, mainScope: CoroutineScope): Listing<Area>
fun worldData(): LiveData<ApiResponse>
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,10 @@ import com.droidteahouse.coronaTracker.vo.ApiResponse
import com.droidteahouse.coronaTracker.vo.Area
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import retrofit2.Response
import java.util.concurrent.Executor
import kotlin.reflect.KFunction1
import kotlin.reflect.KSuspendFunction1

/**
* This boundary callback gets notified when user reaches to the edges of the list such that the
Expand All @@ -46,7 +45,7 @@ class CoronaTrackerBoundaryCallback(
private val networkPageSize: Int)
: PagedList.BoundaryCallback<Area>() {
lateinit var scope: CoroutineScope
lateinit var handleResponse: KFunction1<@ParameterName(name = "body") ApiResponse?, Unit>
lateinit var handleResponse: KSuspendFunction1<@ParameterName(name = "body") ApiResponse?, Unit>
val helper = PagingRequestHelper(ioExecutor)
var networkState = helper.createStatusLiveData() as MutableLiveData

Expand All @@ -58,8 +57,8 @@ class CoronaTrackerBoundaryCallback(
helper.runIfNotRunning(PagingRequestHelper.RequestType.INITIAL) {
scope.launch {
try {
val api = async(Dispatchers.IO) { CoronaTrackerApi.safeApiCall(it, networkState) { webservice.scrape() } }
val response = api.await()
val response = CoronaTrackerApi.safeApiCall(it, networkState) { webservice.scrape() }

if (response != null) {
if (response.isSuccessful) launch(Dispatchers.IO) { insertItemsIntoDb(response, it) } else it.recordFailure(Throwable(response.errorBody().toString()))
}
Expand Down Expand Up @@ -91,18 +90,17 @@ class CoronaTrackerBoundaryCallback(
* every time it gets new items, boundary callback simply inserts them into the database and
* paging library takes care of refreshing the list if necessary.
*/
private fun insertItemsIntoDb(
private suspend fun insertItemsIntoDb(
response: Response<String>,
it: PagingRequestHelper.Request.Callback) {
CoroutineScope(Dispatchers.IO).launch {
try {

try {
handleResponse?.invoke(response.body()?.let { it1 -> ApiResponse.fromString(it1) })
it.recordSuccess()
} catch (e: Exception) {
it.recordFailure(e)
}
}
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.switchMap
import androidx.paging.toLiveData
import androidx.room.withTransaction
import com.droidteahouse.coronaTracker.api.CoronaTrackerApi
import com.droidteahouse.coronaTracker.db.CoronaTrackerDb
import com.droidteahouse.coronaTracker.repository.CoronaTrackerRepository
Expand All @@ -31,8 +32,8 @@ import com.droidteahouse.coronaTracker.vo.ApiResponse
import com.droidteahouse.coronaTracker.vo.Area
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

/**
* Repository implementation that uses a database PagedList + a boundary callback to return a
Expand Down Expand Up @@ -68,9 +69,9 @@ class DbCoronaTrackerRepository(
/**
* Inserts the response into the database while also assigning position indices to items.
*/
private fun insertResultIntoDb(body: ApiResponse?) {
private suspend fun insertResultIntoDb(body: ApiResponse?) {
body?.let { it ->
db.runInTransaction {
db.withTransaction {
db.dao().insertWorld(it)
db.dao().insert(it.areas)
}
Expand All @@ -90,11 +91,11 @@ class DbCoronaTrackerRepository(
networkState.value = NetworkState.LOADING
mainScope.launch {
try {
val api = async(Dispatchers.IO) { CoronaTrackerApi.safeApiCall(null, networkState) { coronaTrackerApi.scrape() } }
val response = api.await()
val response = CoronaTrackerApi.safeApiCall(null, networkState) { coronaTrackerApi.scrape() }

if (response != null) {
if (response.isSuccessful) {
launch(Dispatchers.IO) { updateResult(response.body()?.let { it1 -> ApiResponse.fromString(it1) }) }
withContext(Dispatchers.IO) { updateResult(response.body()?.let { it1 -> ApiResponse.fromString(it1) }) }
networkState.value = (NetworkState.LOADED)
} else {
networkState.value = (NetworkState.error(response.errorBody().toString()))
Expand All @@ -112,7 +113,7 @@ class DbCoronaTrackerRepository(
*
*/
@MainThread
override fun areasOfCoronaTracker(pageSize: Int, ioScope: CoroutineScope, mainScope: CoroutineScope): Listing<Area> {
override suspend fun areasOfCoronaTracker(pageSize: Int, mainScope: CoroutineScope): Listing<Area> {
// create a boundary callback which will observe when the user reaches to the edges of
// the list and update the database with extra data.
// we are using a mutable live data to trigger refresh requests which eventually calls
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class CoronaTrackerActivity : AppCompatActivity() {
product_grid.background = getDrawable(R.drawable.shr_product_grid_background_shape)
}
//product_grid.onTouchEvent()
//add arrow to product grid
}

fun updateData(v: View) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,55 +16,56 @@

package com.droidteahouse.coronaTracker.ui

import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations
import androidx.lifecycle.ViewModel
import androidx.lifecycle.*
import com.droidteahouse.coronaTracker.repository.CoronaTrackerRepository
import com.droidteahouse.coronaTracker.repository.Listing
import com.droidteahouse.coronaTracker.vo.ApiResponse
import com.droidteahouse.coronaTracker.vo.Area
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch


class CoronaTrackerViewModel(
private val repository: CoronaTrackerRepository

) : ViewModel() {

val viewModelJob = SupervisorJob()
private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)
private val ioScope = CoroutineScope(Dispatchers.IO + viewModelJob)

private val uiScope = CoroutineScope(Dispatchers.Main + viewModelScope.coroutineContext)


val worldLiveData: LiveData<ApiResponse> =
repository.worldData()
liveData<ApiResponse>(context = viewModelScope.coroutineContext + Dispatchers.IO) { repository.worldData() }

var worldData: LiveData<String> = Transformations.map(worldLiveData) { data ->
if (data?.totalConfirmed == null) " " else "${data?.totalConfirmed} total ${data?.totalRecovered} recovered"
}


private val repoResult = repository.areasOfCoronaTracker(30, ioScope, uiScope)
private val repoResult = liveData<Listing<Area>>(context = viewModelScope.coroutineContext + Dispatchers.IO) {
emit(repository.areasOfCoronaTracker(30, uiScope))
}

//livedata vs databinding
//a livedata that observes the value of the button in the menu
//mapping that to a repo call
//this vm
val resultList = repoResult.pagedList
val networkState = repoResult.networkState
val refreshState = repoResult.refreshState

val resultList = repoResult.switchMap { it.pagedList }
val networkState = repoResult.switchMap { it.networkState }
val refreshState = repoResult.switchMap { it.refreshState }


fun refresh() {
repoResult.refresh?.invoke()
viewModelScope.launch {
repoResult.value?.refresh?.invoke()
}
}

fun retry() {
val listing = repoResult
listing?.retry?.invoke()
repoResult.value?.retry?.invoke()
}

override fun onCleared() {
viewModelJob.cancel()
super.onCleared()

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ data class Area(

@Ignore
var percentageRecovered: Double =
if (totalRecovered == "" || totalRecovered == "" || totalRecovered?.replace(",", "")!!.toInt() == 0) 0.0 else totalRecovered?.replace(",", "")!!.toDouble() / (totalConfirmed.replace(",", "").toDouble() - (totalDeaths?.replace(",", "")!!.toDouble())) * 100.00
if (totalRecovered.isNullOrBlank() || totalRecovered is String || totalRecovered == "" || totalRecovered?.replace(",", "")!!.toInt() == 0) 0.0 else totalRecovered?.replace(",", "")!!.toDouble() / (totalConfirmed.replace(",", "").toDouble() - (totalDeaths?.replace(",", "")!!.toDouble())) * 100.00

override fun hashCode(): Int {
return id.hashCode()
Expand Down
1 change: 1 addition & 0 deletions versions.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ kotlin.stdlib = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$versions.kotlin"
kotlin.test = "org.jetbrains.kotlin:kotlin-test-junit:$versions.kotlin"
kotlin.plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlin"
kotlin.allopen = "org.jetbrains.kotlin:kotlin-allopen:$versions.kotlin"
kotlin.reflect = "org.jetbrains.kotlin:kotlin-reflect:$versions.kotlin"
deps.kotlin = kotlin

def lifecycle = [:]
Expand Down

0 comments on commit 682c8ed

Please sign in to comment.