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. 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. 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.
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. Here are the relevant parts of my code. First, the XML layout:
<?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. 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"
. 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. 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. I made the following additions/changes in my layout XML, which gets me a bit further:
<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. 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
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
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? When you set it manually you're explicitly telling it to do that by using the @drawable
syntax
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. Maybe you could do something similar to get the drawable you need
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.