https://kotlinlang.org logo
#android
Title
# android
s

silvio

12/11/2019, 3:12 PM
Hey guys, could anyone tell me why my app crashes when I'm in flight mode and making an API call via retrofit? shouldn't it just return null, or does it throw some exception which I don't know?
stackoverflow 2
d

Diego Almeida de Oliveira

12/11/2019, 3:26 PM
It's hard to tell without any code
s

silvio

12/11/2019, 3:30 PM
this is the api interface
Copy code
interface MLSAPI {
    @POST("geolocate?key=test")
    fun getMLSLocation(@Body mlsRequest: MLSRequest?): Call<MLSResponse?>?
}
this is the request object
Copy code
data class MLSRequest(
    val carrier: String?,
    val cellTowers: List<CellTowerInfo?>?,
    val considerIp: Boolean?,
    val homeMobileCountryCode: Int?,
    val homeMobileNetworkCode: Int?,
    val wifiAccessPoints: List<WifiAccessPointInfo?>?
) {
    override fun toString(): String {
        return GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create().toJson(this).toString()
    }
}
this is the response object
Copy code
data class MLSResponse(
    val accuracy: Double?,
    val error: Error?,
    val fallback: String?,
    val location: Location?
)

data class Location(
    val lat: Double?,
    val lng: Double?
)

data class Error(
    val code: Int?,
    val errors: List<ErrorX>?,
    val message: String?
)

data class ErrorX(
    val domain: String?,
    val message: String?,
    val reason: String?
)
this is where i make the call
Copy code
private fun getMLSPosition(mlsRequest: MLSRequest): Position? {
    val mlsResponse: MLSResponse?

    val response: Response<MLSResponse?>? = mlsAPI.getMLSLocation(mlsRequest)?.execute()

    return if (response != null && response.isSuccessful) {
        mlsResponse = response.body()
        val mlsResponseCopy = mlsResponse!!.copy()
        validateAndConvertMLSResponse(mlsResponseCopy)
    } else {
        null
    }
}
it crashes when it reaches the line before the return and log doesn't say anything
k

KamilH

12/11/2019, 4:18 PM
First of all
mlsAPI.getMLSLocation(mlsRequest)?.execute()
will block your’s app Main Thread which is probably the reason of the crash. To be able to execute this piece of code you need to switch your Thread to background one. There are a lot of good resources describing how to do that, but when you are in Kotlin context already, then I would suggest to use
Kotlin Coroutines
. You can also use
enqueue
instead of
execute
, but then you need to use Callbacks. Second problem I can see - the same line of code will crash your app in case of
IOException
or
HttpException
. To prevent this, you need to try-catch it, here is the simplest version:
Copy code
val response = try {
 mlsAPI.getMLSLocation(mlsRequest)?.execute()
} catch (e: Exception) {
 null
}
response
will be null in case there is any exception thrown. But to be honest - don’t do that. Handle this exception in different way. There are a lot of articles how to do that in a proper way 🙂
s

silvio

12/11/2019, 4:23 PM
Thank you. Haven't seen that it throws IOException, because Kotlin doesn't have checked Exceptions. Also the method that calls this one is uses an IODispatcher coroutine, so there's no problem with blocking (and shouldn't the execute method be suspend when it's blocking? or is this because it is a java method?). It was just that I've overlooked the Exception because I didn't know it could occur.
3 Views