Android App Bundle: Load Drawable Resources From Dynamic Feature Modules

November 18, 2019

Refer to Launch Activity from Dynamic Feature Modules for setup.

I am using getQuoteMakerModule code from Load Dynamic Feature Modules with ViewModel and Helper Class to load a dynamic feature module.

class DailyQuoteActivity : AppCompatActivity() {
    private val viewModel by viewModels<DailyQuoteViewModel>()

    override fun attachBaseContext(base: Context) {
        // if need to access language resources from dynamic modules
        /*
        val configuration = Configuration()
        configuration.setLocale(Locale.forLanguageTag("en"))
        val context = base.createConfigurationContext(configuration)
        super.attachBaseContext(context)
         */
        super.attachBaseContext(base)
        // required to access resources (e.g. drawable) from dynamic modules
        SplitCompat.install(this)
    }


    fun loadDrawableFromModule() {
        viewModel.getQuoteMakerModule { success ->
            if (success) {
                // a resource id from dynamic modules
                val moduleResourceId = ...

                if (viewModel.needSplitCompatInstall) {
                    Timber.d("SplitCompat.install")

                    // you can access drawable via applicationContext without SplitCompat.install
                    val d = AppCompatResources.getDrawable(applicationContext, moduleResourceId)

                    // should be able to access resources via a new context
                    val newContext = context.createPackageContext(context.packageName, 0)
                    val d2 = AppCompatResources.getDrawable(newContext, moduleResourceId)

                    // need this to access drawable from module during first install
                    SplitCompat.install(context)
                    viewModel.needSplitCompatInstall = false
                }

                // access drawable via activity context require SplitCompat.install
                // , else Resources.NotFoundException exception is thrown
                val d = AppCompatResources.getDrawable(context, moduleResourceId)
                imageView.setImageResource(moduleResourceId)

            }
        }
    }
}

More about Resources

You can save resources id of dynamic feature module in database

val resourceId = R.drawable.sticker_cool

I am not sure how reliable is the resource id (as in whether the id would remain persistent between compilation). A safer method would be to save the resource name.

val resourceName = resources.getResourceEntryName(R.drawable.sticker_cool) // "sticker_cool"

You can get the resource id of the Dynamic Feature Modules’ resources via name in Base Module

val baseModulePackage = "com.luasoftware.nuanxin"
val dynamicModuleName = "quotemaker"
val packageName = "$baseModulePackage.$dynamicModuleName"
val resourceId = resources.getIdentifier("sticker_cool", "drawable", packageName)

NOTE: Note that the packageName for dynamic feature module is pretty tricky (the actual package name for my dynamic feature module is com.luasoftware.quotemaker while the module name is quotemaker).

This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.