PhillyTheThrilly
PhillyTheThrilly

Reputation: 1842

How do I handle process recreation in android when application startup relies on a network call?

Say I have a custom application in class in my Android app that makes a network call, asynchronously, on startup. Then I have a Main activity that needs the results of the network call on startup. I can handle this with a Splash activity that waits on app startup. But when the process is recreated, we go straight to the Main activity, which expects the results of the network call to be there, and it crashes.

See the code below for an example.

What's the best way to handle this? I want to keep the splash screen for normal startup situations. But in the second situation, where the app is recreated, I'm not sure how to handle it. Is there a way to show the splash screen again, and wait, before returning to the recreated Main activity?

class MyApplication : Application() {

    private val scope = CoroutineScope(Dispatchers.Main)

    companion object {
        lateinit var version: Integer
        var startupFinishedListener: (() -> Unit)? = null
    }

    override fun onCreate() {
        super.onCreate()
        scope.launch {
            version = getVersionFromNetwork() //Fake suspending network call
            startupFinishedListener?.invoke()
        }
    }
}
class SplashScreen : Activity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.splash)
        MyApplication.startupFinishedListener = {
            startMainActivity()
        }
    }

    fun startMainActivity() {
        val intent = Intent(this, MainActivity::class.java)
        startActivity(intent)
    }
}
class MainActivity : Activity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)

        //This line will crash if we are coming from an activity recreation
        Timber.d("Version is: ${MyApplication.version}")
    }
}

I would prefer not to solve this by doing work in onResume in all of my activities instead of onCreate(). Ideally I could tell Android to launch my Splash activity before it launches the restored activity.

Upvotes: 4

Views: 892

Answers (2)

Maulik Hirani
Maulik Hirani

Reputation: 1923

"This looks like an Architectural Problem."

Calling an API into application class and registering it's listener to your activities is a bad idea!

There are few options for you to handle your requirement:

  1. If the data you want is really that important in MainActivity, you can call the API in MainActivity onCreate() itself with some loading indicator before your actual data is loaded.

What will happen if process restarts in this case?

Your MainActivity will recreate and call the API again. So, you're good.

  1. If you're required to have that data as soon as your MainActivity starts, without waiting, you need to do caching. Call your API in splash activity and save the data to a file, shared preference or database. Then access cached data in your MainActivity.

What will happen if process restarts in this case?

Since you've already cached your data into a persitent storage, it'll be there even after process restart. So, you're good to get your data back.

Bonus

If you don't want to use your cached data everytime you open your app, just clear the cache in your SplashActivity and call the API everytime to have the latest data with you before moving to MainActivity.

Upvotes: 2

Yunus Kulyyev
Yunus Kulyyev

Reputation: 1022

You will have to handle this in your onResume() lifecycle. You can create an onResume and then call the SplashActivity intent and finish() your MainActivity. This way it will just go back to Splash Screen where it will load the data and call the Main Activity again

override fun onResume() {
     super.onResume()
     val intent = Intent(this,SplashActivity)
     startActivity(intent)
}

Upvotes: 2

Related Questions