Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/231.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
当创建Android Jetpack Compose AndroidView的参数发生变化时,如何使其被替换?_Android_Kotlin_Android View_Android Jetpack Compose - Fatal编程技术网

当创建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])