My app has a specific requirement of uploading files as multipart using retrofit and LiveData in the background(App Navigation works while uploading data to the server.). The app requires chained network requests on the bases of the response it gets. I've used the Foreground service for network requests. this procedure works well in Android 9,10,11.
UploadFragment.kt
class UploadFragment : BaseFragment() {
....
private fun uploadFilesToServer() {
val intent = Intent(requireActivity(), MyFileUploadingService::class.java)
ContextCompat.startForegroundService(requireActivity(), intent)
}
}
FileUploadService.kt
class FileUploadService : LifecycleService() {
....
private fun registerObservers() {
viewModel?.uploadLiveData!!.observe(this) { response ->
val dataResponse: DataUploadResponse = response.responseBody!!.data!!
if (dataResponse.error == null) {
....
// Repeat
} else {
stopSelf()
}
}
}
}
I'm getting an error while observing response using LiveData.
val dataResponse: DataUploadResponse = response.responseBody!!.data!!
Error Log
2022-08-24 13:08:59.792 26140-26140/com.myapp.demo E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.myapp.demo, PID: 26140
java.lang.NullPointerException
at com.myapp.demo.service.FileUploadService$registerObservers$1.onChanged(FileUploadService.kt:242)
at com.myapp.demo.service.FileUploadService$registerObservers$1.onChanged(FileUploadService.kt:54)
at androidx.lifecycle.LiveData.considerNotify(LiveData.java:133)
at androidx.lifecycle.LiveData.dispatchingValue(LiveData.java:151)
at androidx.lifecycle.LiveData.setValue(LiveData.java:309)
at androidx.lifecycle.MutableLiveData.setValue(MutableLiveData.java:50)
at androidx.lifecycle.LiveData$1.run(LiveData.java:93)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7870)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
The crash is not Android 12–specific — it’s a NullPointerException
caused by using !!
on a value that can be null
:
val dataResponse: DataUploadResponse = response.responseBody!!.data!!
At least one of response
, response.responseBody
, or response.responseBody.data
is null
. On Android 9–11 it probably didn’t hit that case during your tests, but the code is still unsafe.
Handle nulls defensively instead of forcing with !!
:
viewModel?.uploadLiveData?.observe(this) { response ->
val dataResponse = response.responseBody?.data
if (dataResponse != null && dataResponse.error == null) {
// proceed with next upload
} else {
stopSelf()
}
}
Or, short-circuit more clearly:
viewModel?.uploadLiveData?.observe(this) { response ->
val dataResponse = response.responseBody?.data ?: run {
stopSelf()
return@observe
}
if (dataResponse.error == null) {
// repeat
} else {
stopSelf()
}
}
!!
with network responses. Retrofit can return a null
body on error, so always guard against it.Success
, Error
, Loading
) so your observer logic is safer and easier to chain.startForeground()
with a valid notification within 5 seconds, or the system may kill the service.