Search code examples
androidkotlingoogle-cloud-firestoregoogle-tasks-api

Getting rid of nested Task type


Is it possible to get rid of nested Task generics?

For every continueWith statement, a new Task is added within the type. Every continuation is part of the type. Ideally I would return one Task which consecutively executes every single task and succeeds or fails as one.

Example

The first operations queries the groups of a user

private fun getGroupsSnapshot(): Task<QuerySnapshot> {
    val userId = Auth.currentUser()!!.uid
    val query = userGroupsQuery(groupsCollection, userId)
    return query.get()
}

The second operation queries albums within those groups.

fun getAlbums(): Task<Task<List<Album>>> {
    return getGroupsSnapshot().continueWith { task ->
        val documentSnapshots = TaskUtils.getResult(task)
        val albums = mutableListOf<Album>()
        val fetchAlbumTasks = documentSnapshots.documents.map { document ->
            Log.d(TAG, document["name"].toString())
            document.reference.collection("albums").get().addOnCompleteListener { queryTask ->
                albums.addAll(toObjects(Album::class.java, queryTask))
            }
        }
        return@continueWith Tasks.whenAll(fetchAlbumTasks).continueWith allTasks@ {
            return@allTasks albums as List<Album>
        }
    }
}

However I would like this operation to return type Task<List<Album>> to keep the interface clean.


Solution

  • For composing multiple Task you should use continueWithTask instead of continueWith. It accepts a Continuation<TResult, Task<TContinuationResult> as a parameter, which essentially flattens the returning Task and avoids nesting. You should think of it as map vs flatMap operation in Monads (i.e. List), in this case, continueWithTask would be the equivalent of flatMap if you use List as the container instead of Task (Remember, with flatMap you transform every element of the List to a new List, and flatten the resulting List)