{"record":{"id":"8962181e81f10118","repo":"Tencent/QMUI_Android","slug":"view-s-rootview-s-context-is-not-appcompatactivity","errorCode":null,"errorMessage":"view's rootView's context is not AppCompatActivity","messagePattern":"view's rootView's context is not AppCompatActivity","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"compose/src/main/java/com/qmuiteam/compose/modal/QMUIModal.kt","lineNumber":108,"sourceCode":"    fun doOnShow(listener: Action): QMUIModal\n    fun doOnDismiss(listener: Action): QMUIModal\n    fun removeOnShowAction(listener: Action): QMUIModal\n    fun removeOnDismissAction(listener: Action): QMUIModal\n\n    fun interface Action {\n        fun invoke(modal: QMUIModal)\n    }\n}\n\nfun interface ModalHostProvider {\n    fun provide(view: View): Pair<FrameLayout, OnBackPressedDispatcher>\n}\n\nclass ActivityHostModalProvider : ModalHostProvider {\n    override fun provide(view: View): Pair<FrameLayout, OnBackPressedDispatcher> {\n        val contentLayout =\n            view.rootView.findViewById<FrameLayout>(Window.ID_ANDROID_CONTENT) ?: throw RuntimeException(\"View is not attached to Activity\")\n        val activity = contentLayout.context as? AppCompatActivity ?: throw RuntimeException(\"view's rootView's context is not AppCompatActivity\")\n        return contentLayout to activity.onBackPressedDispatcher\n    }\n}\n\nval DefaultModalHostProvider = ActivityHostModalProvider()\n\nfun View.qmuiModal(\n    mask: Color = DefaultMaskColor,\n    systemCancellable: Boolean = true,\n    maskTouchBehavior: MaskTouchBehavior = MaskTouchBehavior.dismiss,\n    uniqueId: Long = SystemClock.elapsedRealtimeNanos(),\n    modalHostProvider: ModalHostProvider = DefaultModalHostProvider,\n    enter: EnterTransition = fadeIn(tween(), 0f),\n    exit: ExitTransition = fadeOut(tween(), 0f),\n    content: @Composable AnimatedVisibilityScope.(QMUIModal) -> Unit\n): QMUIModal {\n    if (!isAttachedToWindow) {\n        throw RuntimeException(\"View is not attached to window\")","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/Tencent/QMUI_Android/blob/026e7d486677d6593a96689cd590ec3561176717/compose/src/main/java/com/qmuiteam/compose/modal/QMUIModal.kt#L90-L126","documentation":"After finding the android.R.id.content FrameLayout, provide() casts its context to AppCompatActivity. If the context is not an AppCompatActivity (different Activity base class, Service, Application, or wrapped ContextThemeWrapper), the safe cast fails and a RuntimeException is thrown because OnBackPressedDispatcher is read from AppCompatActivity.","triggerScenarios":"Calling a qmui modal API with a view whose Activity host extends Activity/AppCompatActivity-like other base (e.g. ComponentActivity, FragmentActivity) or whose content view's context is wrapped or non-Activity.","commonSituations":"App migrated to ComponentActivity/FragmentActivity while QMUI requires AppCompatActivity; using ApplicationContext-inflated views; theme-wrapped contexts that break the direct cast.","solutions":["Make the hosting Activity extend androidx.appcompat.app.AppCompatActivity.","Unwrap ContextThemeWrapper chains in a custom ModalHostProvider to find the underlying Activity.","Implement ModalHostProvider yourself returning contentLayout and the dispatcher from whatever Activity type you use.","Check the Activity base class before invoking the modal API."],"exampleFix":"// before\nclass MainActivity : ComponentActivity() { ... } // throws in provide()\n// after\nclass MainActivity : AppCompatActivity() { ... }","handlingStrategy":"type-guard","validationCode":"fun requiresAppCompat(view: View): Boolean {\n  val ctx = view.context\n  return ctx is AppCompatActivity || (ctx is ContextWrapper && ctx.baseContext is AppCompatActivity)\n}","typeGuard":"fun View.appCompatActivity(): AppCompatActivity? =\n  generateSequence(context as? ContextWrapper) { it.baseContext as? ContextWrapper }\n    .filterIsInstance<AppCompatActivity>().firstOrNull()","tryCatchPattern":"try { view.qmuiBottomSheet { ... } } catch (e: RuntimeException) { fallbackToPlainDialog() }","preventionTips":["Make Activities extend AppCompatActivity","Unwrap ContextThemeWrapper before asserting the Activity type","Provide a custom ModalHostProvider for non-AppCompat hosts"],"tags":["android","ui","modal","type-cast","appcompat"],"backgroundTag":"incompatible-source-type","analyzedSha":"026e7d486677d6593a96689cd590ec3561176717","analyzedAt":"2026-09-06T13:32:24.816Z","contentChangedAt":"2026-09-06T13:32:24.816Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}