如何在Android Library模块中正确使用AndroidViewModel
Library模块无法获取Application初始化ViewModel的解决方案
问题根因
Android Library模块本身没有独立的Application生命周期,所有运行时上下文都来自依赖该Library的宿主Application模块,因此无法在Library内部直接获取Application实例,导致自定义Factory无法初始化,触发ViewModel创建失败崩溃。
方案1:显式初始化入口(推荐,可控性最高)
在Library内部提供全局初始化方法,要求宿主App集成时在自身Application中传入实例完成初始化:
- Library内部编写全局配置单例:
object LibraryCore { private var _application: Application? = null val application: Application get() = _application ?: throw IllegalStateException("请先调用LibraryCore.init(application)完成Library初始化") // 宿主App在Application.onCreate中调用该方法 fun init(application: Application) { _application = application } }
- 宿主App的Application类中完成初始化:
class HostApp : Application() { override fun onCreate() { super.onCreate() // 初始化依赖的Library LibraryCore.init(this) } }
- 后续Library内任意需要Application的场景直接调用
LibraryCore.application即可,初始化ViewModel Factory示例:
val viewModel = ViewModelProvider( this, LanguageViewModelProvider(LibraryCore.application) )[LanguageViewModel::class.java]
方案2:自动初始化(无需宿主手动操作)
如果希望降低宿主集成成本,可以通过自定义ContentProvider自动获取上下文完成初始化,无需宿主额外编码:
- 复用方案1中的
LibraryCore单例,新增初始化用ContentProvider:
class LibraryInitProvider : ContentProvider() { override fun onCreate(): Boolean { (context?.applicationContext as? Application)?.let { LibraryCore.init(it) } return true } // 其余方法无需实现,返回默认值即可 override fun query(uri: Uri, projection: Array<out String>?, selection: String?, selectionArgs: Array<out String>?, sortOrder: String?): Cursor? = null override fun getType(uri: Uri): String? = null override fun insert(uri: Uri, values: ContentValues?): Uri? = null override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?) = 0 override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array<out String>?) = 0 }
- 在Library模块的
AndroidManifest.xml中注册该Provider:
<provider android:name=".LibraryInitProvider" android:authorities="${applicationId}.library_init_provider" android:exported="false" />
Library集成到宿主后会自动触发ContentProvider创建,拿到全局Application实例完成初始化。
方案3:宿主直接传参实例化
如果不想修改Library内部逻辑,可以直接要求宿主在实例化ViewModel时传入自身Application:
// 宿主Activity/Fragment内初始化代码示例 val factory = LanguageViewModelProvider(applicationContext as Application) val viewModel = ViewModelProvider(this, factory)[LanguageViewModel::class.java]
注意事项
上述方案中持有的都是全局Application实例,不会产生内存泄漏问题;如果使用显式初始化方案,建议添加初始化状态判断,避免未初始化直接调用导致崩溃。
内容的提问来源于stack exchange,提问作者Ahmet B.
相关产品推荐
相关产品推荐

