I'm trying to launch a fragment in my a dynamic feature module using a ServiceLoader as follows, but I get a crash the first time I try to launch my fragment. After the initial crash, if I try to launch the fragment again, it loads fine.
I am checking if the module is installed before trying to launch the fragment. Why am I still getting this first-time crash? It's almost as if the serviceLoader isn't fully loaded unless I leave the app idle for another second.
splitInstallManager = SplitInstallManagerFactory.create(this)
val request = SplitInstallRequest
.newBuilder()
.addModule("dynamicFragment")
.build()
splitInstallManager.startInstall(request)
.addOnSuccessListener { sessionId ->
if (!splitInstallManager.installedModules.contains("dynamicFragment"))
return@addOnSuccessListener
findViewById<TextView>(R.id.installStatus).text = "Successfully installed dynamic module, sessionId=$sessionId"
val launch = findViewById<Button>(R.id.launchFragmentBtn)
launch.visibility = View.VISIBLE
launch.setOnClickListener {
val serviceLoader = ServiceLoader.load(
DynamicFragmentContract.Provider::class.java,
DynamicFragmentContract.Provider::class.java.classLoader)
val c: DynamicFragmentContract = serviceLoader.iterator().next().get()
val fragment = c as Fragment
supportFragmentManager
.beginTransaction().add(R.id.fragmentContainer, f).commit()
2022-03-25 21:06:31.960 18125-18125/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.myapp.dynamicfeaturemodulesapp, PID: 18125
java.util.NoSuchElementException
at java.util.ServiceLoader$LazyIterator.nextService(ServiceLoader.java:366)
at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:416)
at java.util.ServiceLoader$1.next(ServiceLoader.java:494)
at com.myapp.mylibrary.LibraryActivity.onCreate$lambda-3$lambda-1$lambda-0(LibraryActivity.kt:61)
at com.myapp.mylibrary.LibraryActivity.$r8$lambda$_Qbmh4qCZoH4E5ov5s1Js7ZPauo(Unknown Source:0)
at com.myapp.mylibrary.LibraryActivity$$ExternalSyntheticLambda1.onClick(Unknown Source:2)
Turns out
splitInstallManager.addOnSuccessListener
wasn't reliably reflecting the download/install status. After I changed it to use theSplitInstallStateUpdatedListener
, things are working as expected.