[英]Android Kotlin: Setting fragment TextView background on start from ViewModel
I am confused by a certain inconsistency in my code, where only part of the data is loading.我对我的代码中的某些不一致感到困惑,其中只有部分数据正在加载。 I am trying to set up a grid of TextViews in my fragment, which read from a list variable called board on the ViewModel for that fragment.
我正在尝试在我的片段中设置一个 TextViews 网格,该网格从该片段的 ViewModel 上名为board的列表变量中读取。 The TextView text is set as board[n].text from the view model, where n is its index in the list, and this loads just fine.
TextView 文本被设置为来自视图模型的board[n].text ,其中 n 是它在列表中的索引,这加载得很好。 I am also trying to set the TextView background to one of three background resources, which are saved as an int board[n].marking on the view model.
我还尝试将 TextView 背景设置为三个背景资源之一,这些资源在视图模型上保存为 int board[n].marking 。
This does not work.这不起作用。 It seems that it is trying to load the background for each TextView before board has been fully initialized in the view model, but it does not seem to try to do the same for the TextView text.
似乎它正在尝试在视图模型中完全初始化board之前为每个 TextView 加载背景,但它似乎并没有尝试为 TextView 文本做同样的事情。 Here are the relevant parts of my code.
这是我的代码的相关部分。 First, the XML layout:
一、XML布局:
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".screens.game.GameFragment">
<data>
<import type="android.view.View"/>
<variable
name="gameViewModel"
type="com.example.mygametitle.screens.game.GameViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
(...)
<TextView
android:id="@+id/field13"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="@dimen/board_vertical_margin"
android:background="@{gameViewModel.board[2].marking}"
android:onClick="@{ () -> gameViewModel.openGameDialog(2, field13)}"
android:text="@{gameViewModel.board[2].text}"
(...)
There are 25 fields like that.有 25 个这样的字段。 All of the text loads properly, but none of the background images load.
所有文本都正确加载,但没有任何背景图像加载。 If instead I hardcode the background I want, as such, it loads properly:
android:background="@drawable/board_fieldbackground_checked"
.相反,如果我硬编码我想要的背景,它会正确加载:
android:background="@drawable/board_fieldbackground_checked"
。 This won't work for me though, as I need to read what each entry's background is upon startup--they don't all start checked.不过,这对我不起作用,因为我需要在启动时阅读每个条目的背景——它们并没有全部开始检查。
On the view model, board is made by reading a set of 25 entries from a Room database, each including (among other info) a text string and a marking int.在视图模型上, board是通过从 Room 数据库读取一组 25 个条目来制作的,每个条目包括(除其他信息外)一个文本字符串和一个标记int。 These all update properly--if I use a debug function to print out the contents of my board, they all have the proper text and marking upon closing and reopening the fragment.
这些都正确更新——如果我使用调试功能打印出我的板的内容,它们在关闭和重新打开片段时都有正确的文本和标记。 When the fragment opens, all the text is correct, but the backgrounds are not.
当片段打开时,所有文本都是正确的,但背景不是。 Any ideas on why my backgrounds aren't loading the same way the text is?
关于为什么我的背景没有以与文本相同的方式加载的任何想法?
Here's some of the relevant viewmodel code:这是一些相关的视图模型代码:
class GameViewModel(
val database: BoardDatabaseDao,
application: Application,
val boardTitle: String) : AndroidViewModel(application) {
val BG_UNMARKED = R.drawable.board_fieldbackground_bordered
val BG_CHECKED = R.drawable.board_fieldbackground_checked
val BG_MISSED = R.drawable.board_fieldbackground_missed
private val thisBoardEntries = MutableLiveData<List<BoardField>?>()
private val _board = MutableLiveData<List<BoardField>>()
val board: LiveData<List<BoardField>>
get() = _board
private suspend fun getEntries() : List<BoardField>? {
Log.i("GameViewModel", "Running database.getFromParent(boardTitle), function getEntries().")
val entries = database.getFromParent(boardTitle)
return entries
}
init {
viewModelScope.launch {
Log.i("GameViewModel", "Start viewModelScope.launch on init block.")
thisBoardEntries.value = getEntries()
if (thisBoardEntries.value?.isEmpty()!!) {
Log.i(
"GameViewModel",
"allEntries.value is EMPTY, seemingly: ${thisBoardEntries.value}, should be empty"
)
} else {
Log.i(
"GameViewModel",
"allEntries.value is NOT empty, seemingly: ${thisBoardEntries.value}, should be size 25"
)
_board.value = thisBoardEntries.value
}
}
}
fun markFieldMissed(index: Int, view: TextView) {
Log.i("GameViewModel", "My Textview looks like this: $view")
_board.value!![index].marking = BG_MISSED
view.setBackgroundResource(BG_MISSED)
Log.i("GameViewModel", "Set background to $BG_MISSED")
val color = getColor(getApplication(), R.color.white_text_color)
view.setTextColor(color)
viewModelScope.launch {
val markedField = getEntryAtIndex(boardTitle, convertIndexToLocation(index))
Log.i("GameViewModel", "I think markedField is $markedField")
if (markedField != null) {
markedField.marking = BG_MISSED
update(markedField)
Log.i("GameViewModel", "Updated field with $BG_MISSED marking on DB: $markedField")
}
}
}
fun markFieldChecked(index: Int, view: TextView) {
_board.value!![index].marking = BG_CHECKED
view.setBackgroundResource(BG_CHECKED)
Log.i("GameViewModel", "Set background to $BG_CHECKED")
val color = getColor(getApplication(), R.color.white_text_color)
view.setTextColor(color)
viewModelScope.launch {
val markedField = getEntryAtIndex(boardTitle, convertIndexToLocation(index))
Log.i("GameViewModel", "I think markedField is $markedField")
if (markedField != null) {
markedField.marking = BG_CHECKED
update(markedField)
Log.i("GameViewModel", "Updated field with $BG_CHECKED marking on DB: $markedField")
}
}
}
fun debugPrintEntries() {
Log.i("GameViewModel", "DebugPrintEntries function: ${_board.value}")
}
(2020-11-05) Edit 1: Part of the issue was indeed a resource not being read as such. (2020-11-05) 编辑 1:问题的一部分确实是没有被这样阅读的资源。 I made the following additions/changes in my layout XML, which gets me a bit further:
我在我的布局 XML 中做了以下添加/更改,这让我更进一步:
<data>
<import type="androidx.core.content.ContextCompat"/>
(...)
</data>
<TextView
(...)
android:background="@{ContextCompat.getDrawable(context, gameViewModel.BG_CHECKED)}"
(...)
With a hardcoded resource for BG_CHECKED as my background image, everything loads and displays nicely.使用 BG_CHECKED 的硬编码资源作为我的背景图像,一切都可以很好地加载和显示。 The problem is once again that the background is not read from
board[4].marking
(which contains BG_CHECKED as its value), although the text has no problem being read from board[4].text
问题再次是背景不是从
board[4].marking
(其中包含 BG_CHECKED 作为其值)读取的,尽管从board[4].text
读取文本没有问题
The following replacement in the layout XML does not work, causing an exception: Caused by: android.content.res.Resources$NotFoundException: Resource ID #0x0
with the line布局 XML 中的以下替换不起作用,导致异常:
Caused by: android.content.res.Resources$NotFoundException: Resource ID #0x0
with the line
android:background="@{ContextCompat.getDrawable(context, gameViewModel.board[4].marking)}"
I haven't used data binding, but I think it might be because you're just providing an Int
as the background, which happens to represent a resource ID - but the data binding doesn't know that, so it doesn't know it needs to resolve it to a drawable value in resources?我没有使用过数据绑定,但我认为这可能是因为你只是提供一个
Int
作为背景,它恰好代表一个资源 ID - 但数据绑定不知道这一点,所以它不知道它需要将其解析为资源中的可绘制值吗? When you set it manually you're explicitly telling it to do that by using the @drawable
syntax当您手动设置它时,您通过使用
@drawable
语法明确告诉它这样做
Here's a blog where someone runs into something similar (well that situation anyway, but with colours) - their second solution is to add a ContextCompat
import to the data
block, and then use that to do a ContextCompat.getColor
lookup in the data binding expression. 这是一个博客,其中有人遇到了类似的事情(无论如何都是这种情况,但是有颜色) - 他们的第二个解决方案是将
ContextCompat
导入添加到data
块,然后使用它在数据绑定表达式中进行ContextCompat.getColor
查找. Maybe you could do something similar to get the drawable you need也许你可以做一些类似的事情来获得你需要的 drawable
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.