当创建Android Jetpack Compose AndroidView的参数发生变化时,如何使其被替换?
我有一个应用程序,它显示了封装在当创建Android Jetpack Compose AndroidView的参数发生变化时,如何使其被替换?,android,kotlin,android-view,android-jetpack-compose,Android,Kotlin,Android View,Android Jetpack Compose,我有一个应用程序,它显示了封装在AndroidView中的几个不同视图。在下面重现的简单示例中,这些只是TextView实例。问题是,更改文本(在本例中,通过三个不同的值循环)似乎不会更新应用程序显示的内容 sealed class AppView data class ShowSomeText(val text: String) : AppView() data class SomeOtherState(val data: Any?) : AppView() data class ShowSo
AndroidView
中的几个不同视图。在下面重现的简单示例中,这些只是TextView
实例。问题是,更改文本(在本例中,通过三个不同的值循环)似乎不会更新应用程序显示的内容
sealed class AppView
data class ShowSomeText(val text: String) : AppView()
data class SomeOtherState(val data: Any?) : AppView()
data class ShowSomeText2(val text: String) : AppView()
class AppViewModel : ViewModel() {
var currentView = MutableLiveData<AppView>(ShowSomeText("original text"))
var currentViewWorkaround = MutableLiveData<AppView>(ShowSomeText("original text"))
private val textRing = arrayOf("one", "two", "three")
private var textRingPosition = 0
fun incrementTextState() {
val nextState = ShowSomeText(textRing[textRingPosition])
currentView.postValue(nextState)
val nextStateWorkaround = when(currentViewWorkaround.value) {
is ShowSomeText -> ShowSomeText2(textRing[textRingPosition])
else -> ShowSomeText(textRing[textRingPosition])
}
currentViewWorkaround.postValue(nextStateWorkaround)
textRingPosition = (textRingPosition + 1) % textRing.size
}
}
class MainActivity : AppCompatActivity() {
private val viewModel = AppViewModel()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ViewContainer(viewModel)
}
}
}
@Composable
fun ViewContainer(viewModel: AppViewModel) {
// Add this to gradle.build for the observeAsState function:
// implementation "androidx.compose.runtime:runtime-livedata:$compose_version"
val currentView: AppView by viewModel.currentView.observeAsState(ShowSomeText("starting text"))
val currentViewWorkaround: AppView by viewModel.currentViewWorkaround.observeAsState(ShowSomeText("starting text"))
Column {
Button(onClick = viewModel::incrementTextState) {
Text(
text = "tap to change",
style = TextStyle(fontSize = 12.em)
)
}
Text("Compose Text")
when (currentView) {
is ShowSomeText -> createComposeTextView((currentView as ShowSomeText).text)
is SomeOtherState -> Text("the other state")
}
Text("AndroidView wrapping TextView")
when (currentView) {
is ShowSomeText -> createAndroidViewForTextView((currentView as ShowSomeText).text)
is SomeOtherState -> Text("the other state")
}
Text("AndroidView wrapping TextView with 2-state workaround")
when (currentViewWorkaround) {
is ShowSomeText -> createAndroidViewForTextView((currentViewWorkaround as ShowSomeText).text)
is ShowSomeText2 -> createAndroidViewForTextView((currentViewWorkaround as ShowSomeText2).text)
is SomeOtherState -> Text("the other state")
}
}
}
@Composable
fun createAndroidViewForTextView(text: String) {
val context = ContextAmbient.current
val tv = remember(text, context) {
val x = TextView(context)
x.text = text
x.textSize = 48.0f
x
}
AndroidView({ tv })
}
@Composable
fun createComposeTextView(text: String) {
Text(text, style = TextStyle(fontSize = 12.em))
}
密封类AppView
数据类ShowSomeText(val text:String):AppView()
数据类SomeOtherState(val数据:有吗?):AppView()
数据类ShowSomeText2(val text:String):AppView()
类AppViewModel:ViewModel(){
var currentView=MutableLiveData索引必须是可变状态,如:textRingPosition=memory{mutableStateOf(0)}
作为一般提示,如果您的撰写代码包含var
,则可能有错误,应该是一种状态
解释:
如果您运行这个代码段,您可以按下按钮,但是composable没有更新,但是在控制台中您可以看到值已更改
Surface(修饰符=modifier.padding(all=16.dp.fillMaxSize()){
val textRing=arrayOf(“一”、“二”、“三”)
var textRingPosition=0
val liveData=MutableLiveData()
val observeastate:liveData.observeastate的字符串(initial=textRing[textRingPosition])
第()列{
println(“由“+observeastate+”和pos:+textRingPosition组成)
文本(“文本:+observeastate”)
按钮(onClick={
textRingPosition=textRingPosition.inc().rem(textRing.size)
println(“OnClick:+textRingPosition)
liveData.postValue(textRing[textRingPosition])
}) {
文本(“更改”)
}
}
}
控制台中的输出:
1 | I/System.out: Composed with one and pos: 0
2 | I/System.out: OnClick: 1
3 | I/System.out: Composed with two and pos: 0
4 | I/System.out: OnClick: 1
5 | I/System.out: OnClick: 2
6 | I/System.out: Composed with three and pos: 0
7 | I/System.out: OnClick: 1
8 | I/System.out: Composed with two and pos: 0
9 | I/System.out: OnClick: 1
在第4行中,您可以看到索引已更改为1
,但它应该已经位于2
,这是因为在第3行中重新组合了视图并重置了索引。由于当前值与状态中的新值相同,因此在这里不需要更新视图,所以组合不会重新组合。在第5行中,索引为2
将状态值更改为另一个字符串,从而触发重新编译
使用索引的记忆和可变状态,组件将重新组合每次更改:
Surface(修饰符=modifier.padding(all=16.dp.fillMaxSize()){
val textRing=arrayOf(“一”、“二”、“三”)
var textRingPosition=0
val liveData=MutableLiveData()
val observeastate:liveData.observeastate的字符串(initial=textRing[textRingPosition])
val rememberTextRingPosition=记住{mutableStateOf(0)}
第()列{
println(“由$observeastate和pos:${textRingPosition}组成,预期值:${rememberTextRingPosition.value}”)
文本(“文本:$observeastate”)
按钮(onClick={
textRingPosition=textRingPosition.inc().rem(textRing.size)
rememberTextRingPosition.value=rememberTextRingPosition.value.inc().rem(textRing.size)
println(“OnClick:var:$textRingPosition记住:${rememberTextRingPosition.value}”)
liveData.postValue(textRing[textRingPosition])
}) {
文本(“更改”)
}
}
}
输出:
1 | I/System.out: Composed with one and pos: 0expected value: 0
2 | I/System.out: OnClick: var:1 remember: 1
3 | I/System.out: Composed with two and pos: 0expected value: 1
4 | I/System.out: OnClick: var:1 remember: 2
5 | I/System.out: Composed with two and pos: 0expected value: 2
6 | I/System.out: OnClick: var:1 remember: 0
7 | I/System.out: Composed with two and pos: 0expected value: 0
8 | I/System.out: OnClick: var:1 remember: 1
由于日志状态,组件每次都会按其应该的方式重新组合,并且状态不会因为“记住”而重置。我不确定您试图实现什么-但我看到的第一点是,您的循环列表内容没有按您希望的方式工作。textRingPosition
将更改其值,但您不会侦听/监视更改你需要告诉Compose这个值可能会改变,为此,你需要一个状态val textRingPosition=memory{mutableStateOf(0)}
。我将状态包装在一个memory中,因为我想在重新编译后保留状态。这些def可能有助于memory这样做:“记住计算产生的值。计算只在合成过程中进行。重新编译将始终返回合成产生的值。”state:“可变状态类是一个single值持有者,其读写操作由Compose观察。此外,对它的写操作作为快照系统的一部分进行处理。在composition过程中,您可能希望使用composables的状态和状态,而不是此工厂函数。对于可读性:而不是TextUnit.Companion.Em(12)
您可以使用em扩展功能,如12.em
我认为正在监视的是val currentView:PostplaneAppView by viewModel.currentView.observeastate(ShowSomeText(“起始文本”))
,如果我做了提议的两个更改中的任何一个,它确实会像预期的那样工作。我花了一分钟时间才弄清楚,但原因正如我所说的,但一开始并不那么明显。请参阅答案:抱歉,但问题的关键是让它与AndroidView包装器一起工作。事实上,如果您交换一个Compose Text元素,我的示例确实会工作。我更新我用要点来阐明我的目标。见这一行:/val nextState=ShowSomeText(textRing[textRingPosition])