android Jetpack合成,使用自定义生命周期/ViewModelStore/SavedStateRegistry Owner时不会触发重组

ih99xse1  于 2022-11-27  发布在  Android
关注(0)|答案(1)|浏览(189)

我试图创建一个覆盖层并将视图附加到WindowManager,我已经通过创建一个实现Lifecycle/ViewModelStore/SavedStateRegistry Owner的类来实现了这一点。但由于某种原因,每当我试图以任何方式使用MutableState或MutableStateFlow显示对话框/更改UI时,都不会触发重组。
有没有人尝试过这样做,并设法找到一个解决方案,触发重组?
下面是我尝试创建和插入视图的方法:

@SuppressLint("InflateParams")
fun showOverlay() {
    synchronized(lock) {
        if (overlay != null || overlay?.parent != null) {
            return
        }
        val viewModel = OverlayViewModel(context.applicationContext as Application)
        var scope: CoroutineScope? = null
        overlay = ComposeView(context).apply {
            setContent {
                Overlay(viewModel)
            }
        }
        drawOverLifecycleOwner = DrawOverLifecycleOwner()
        drawOverLifecycleOwner?.attachToDecorView(overlay)
        val params =
            WindowManager.LayoutParams(
                WindowManager.LayoutParams.MATCH_PARENT,
                WindowManager.LayoutParams.MATCH_PARENT,
                WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
                PixelFormat.TRANSLUCENT
            )
        params.gravity = Gravity.TOP or Gravity.START
        Log.i("ScreenLocker", "Inserting overlay")
        ContextCompat.getMainExecutor(context).execute {
            drawOverLifecycleOwner?.onCreate()
            windowManager.addView(overlay, params)
        }
    }
}

这是自定义生命周期所有者:

import android.view.View
import androidx.lifecycle.*
import androidx.savedstate.SavedStateRegistry
import androidx.savedstate.SavedStateRegistryController
import androidx.savedstate.SavedStateRegistryOwner
import androidx.savedstate.ViewTreeSavedStateRegistryOwner

class DrawOverLifecycleOwner : LifecycleOwner, ViewModelStoreOwner, SavedStateRegistryOwner {

    fun onCreate() {
        savedStateRegistryController.performRestore(null)
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
    }

    fun onResume() {
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
    }

    fun onPause() {
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    }

    fun onDestroy() {
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
        savedStateRegistryController.performSave(Bundle())
        store.clear()
    }

    /**
    Compose uses the Window's decor view to locate the
    Lifecycle/ViewModel/SavedStateRegistry owners.
    Therefore, we need to set this class as the "owner" for the decor view.
     */
    fun attachToDecorView(decorView: View?) {
        if (decorView == null) return

        ViewTreeLifecycleOwner.set(decorView, this)
        ViewTreeViewModelStoreOwner.set(decorView, this)
        ViewTreeSavedStateRegistryOwner.set(decorView, this)
    }

    // LifecycleOwner methods
    private val lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(this)

    override fun getLifecycle(): Lifecycle = lifecycleRegistry

    // ViewModelStore methods
    private val store = ViewModelStore()
    override fun getViewModelStore(): ViewModelStore = store

    // SavedStateRegistry methods
    private val savedStateRegistryController = SavedStateRegistryController.create(this)
    override val savedStateRegistry: SavedStateRegistry
        get() = savedStateRegistryController.savedStateRegistry
}

这是覆盖图:

@Composable
fun Overlay(viewModel: OverlayViewModel = viewModel()) {
    val showDialog = remember { MutableStateFlow(false) }
    AppTheme {
        Logger.info("Recomposition triggered")
        ConstraintLayout(
            modifier = Modifier
                .fillMaxSize()
                .background(Color.Black)
        ) {
            val (dialog) = createRefs()
            Box(modifier = Modifier.fillMaxSize()) {
                Text(
                    modifier = Modifier
                        .align(Alignment.TopEnd)
                        .padding(top = 25.dp, end = 15.dp),
                    text = "© 2022",
                    color = Color.White
                )
                Column(
                    modifier = Modifier.align(Alignment.Center),
                    horizontalAlignment = Alignment.CenterHorizontally
                ) {
                    Image(
                        modifier = Modifier
                            .fillMaxWidth()
                            .padding(15.dp),
                        painter = painterResource(R.drawable.logo),
                        contentDescription = "Logo",
                        contentScale = ContentScale.Fit,
                    )
                    Text(
                        modifier = Modifier.padding(bottom = 25.dp),
                        text = "Overlay Text",
                        textAlign = TextAlign.Center,
                        color = Color.White,
                        fontWeight = FontWeight.Bold,
                        style = MaterialTheme.typography.headlineMedium
                    )
                    LazyRow {
                        items(LockService.whitelistedApps) { app ->
                            Button(
                                onClick = { viewModel.launchApp(app) },
                                colors = ButtonDefaults.buttonColors(
                                    containerColor = Color.Transparent
                                )
                            ) {
                                Column(horizontalAlignment = Alignment.CenterHorizontally) {
                                    viewModel.getPackageIcon(app)?.apply {
                                        Image(
                                            this.asImageBitmap(),
                                            contentDescription = "App Icon"
                                        )
                                    }
                                    Text(
                                        text = viewModel.getPackageLabel(app),
                                        color = Color.White
                                    )
                                }
                            }
                        }
                    }
                }
                IconButton(
                    modifier = Modifier
                        .align(Alignment.BottomStart)
                        .padding(bottom = 15.dp, start = 15.dp),
                    onClick = {
                        Logger.info("Trying to show dialog, showDialogValue = ${showDialog.value}")
                        showDialog.tryEmit(true)
                    }
                ) {
                    Icon(
                        imageVector = Icons.Default.Info,
                        contentDescription = "Info Dialog Icon",
                        tint = Color.White
                    )
                }
            }
            if (showDialog.collectAsState().value) {
                InfoDialog(showDialog, Modifier.constrainAs(dialog) {
                    top.linkTo(parent.top)
                    bottom.linkTo(parent.bottom)
                    start.linkTo(parent.start)
                    end.linkTo(parent.end)
                })
            }
        }
    }
}

@Preview
@Composable
fun OverlayPreview() {
    AppTheme {
        Overlay(OverlayViewModel(Application()))
    }
}
nwo49xxi

nwo49xxi1#

嘿,我发现我的实现中有什么问题,你的实现可能也有同样的问题。
当您强制将lifecycleOwner设置为ComposeView时,是否也设置了ON_START事件?在我的视图中,它是缺失的,当我这样做时,Composable开始响应新状态。

val viewModelStore = ViewModelStore()
        lifecycleOwner.performRestore(null)
        lifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
        lifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_START)
        ViewTreeLifecycleOwner.set(composeView, lifecycleOwner)
        ViewTreeViewModelStoreOwner.set(composeView) { viewModelStore }
        it.setViewTreeSavedStateRegistryOwner(lifecycleOwner)

相关问题