#mvvm #kotlin #surfaceview #android-room #android-livedata
#mvvm #kotlin #surfaceview #android-комната #android-livedata
Вопрос:
Я настраиваю базу данных комнат в своем приложении и хочу получать данные от пользователя, который рисует в пользовательском виде поверхности.
Приложение запущено на Android 9, используя шаблон MVVM, я попробовал приложение без места, и оно работало должным образом. После внедрения Room приложение больше не отслеживает изменения данных. Я использовал Google codelabs в качестве шаблона для своего приложения. Пользователь рисует узлы графика в представлении поверхности, нажав на просмотр, и я хочу сохранить данные о месте (узле) в базе данных.
Разместить:
@Entity(tableName = "places")
data class Place(
@Embedded
var mPosition: Point,
@PrimaryKey(autoGenerate = false)
@ColumnInfo(name = "place_id")
var mID: Int = -1,
@ColumnInfo(name = "name")
override var mName: String = "",
@ColumnInfo(name = "tokens")
var mTokens: Int = 0
) : Node() {
override fun isValid(): Boolean {
return mID == -1 amp;amp; mPosition.x != 0f amp;amp; mPosition.y != 0f amp;amp; mTokens >= 0
}
}
PlaceDao:
@Dao
interface PlaceDao {
@Insert
fun addPlace(place: Place)
@Query("SELECT * FROM places ORDER BY place_id ASC")
fun getPlaces(): LiveData<List<Place>>
...
}
База данных:
@Database(entities = [Place::class, Transition::class, Arc::class], version = 1)
@TypeConverters(Converter::class)
abstract class AppRoomDatabase : RoomDatabase() {
abstract fun placeDao(): PlaceDao
companion object {
@Volatile
private var INSTANCE: AppRoomDatabase? = null
fun getDatabase(
context: Context,
scope: CoroutineScope
): AppRoomDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
AppRoomDatabase::class.java,
"word_database"
)
.fallbackToDestructiveMigration()
.addCallback(AppDatabaseCallback(scope))
.build()
INSTANCE = instance
instance
}
}
private class AppDatabaseCallback(
private val scope: CoroutineScope
) : RoomDatabase.Callback() {
override fun onOpen(db: SupportSQLiteDatabase) {
super.onOpen(db)
INSTANCE?.let { database ->
scope.launch(Dispatchers.IO) {
populateDatabase(database.placeDao(),database.transitionDao(),database.arcDao())
}
}
}
}
}
}
Репозиторий:
class NetRepositoryImpl(
private val placeDao: PlaceDao,
private val transitionDao: TransitionDao,
private val arcDao: ArcDao
) : NetRepository {
@WorkerThread
override suspend fun addPlace(place: Place) {
placeDao.addPlace(place)
}
override fun getPlaces() = placeDao.getPlaces()
}
ViewModel:
class NetViewModel(application: Application) : AndroidViewModel(application) {
private var parentJob = Job()
private val coroutineContext: CoroutineContext
get() = parentJob Dispatchers.Main
private val scope = CoroutineScope(coroutineContext)
private val netRepository: NetRepositoryImpl
val allPlaces: LiveData<List<Place>>
...
init {
val placeDao = AppRoomDatabase.getDatabase(application, scope).placeDao()
...
netRepository = NetRepositoryImpl(placeDao, transitionDao, arcDao)
allPlaces = netRepository.getPlaces()
...
}
fun addPlace(place: Place) {
if (place.isValid())
scope.launch(Dispatchers.IO) { netRepository.addPlace(place) }
}
Активность:
class EditorActivity : FragmentActivity() {
private lateinit var viewModel: NetViewModel
override fun onCreate(savedInstanceState: Bundle?) {
...
viewModel = ViewModelProviders.of(this).get(NetViewModel::class.java)
viewModel.apply {
allPlaces.observe(this@EditorActivity, Observer { places ->
editorDrawer.mPlaces = places
Log.d("Editor activity", "Places observed")
})
...
editorDrawer.setOnTouchListener { v, event ->
when (event?.action) {
MotionEvent.ACTION_DOWN -> {
...
viewModel.addPlace(Point(event.x, event.y))
...
}
}
...
}
editorDrawer — это пользовательский вид поверхности в макете активности.
Когда пользователь нажимает на surface view, я ожидаю создать новое место и сохранить его в базе данных, затем нарисовать его в surface view при изменении данных создается новый экземпляр place, но не сохраняется, и никаких изменений не наблюдается, поэтому место не отображается. Я могу найти в журнале консоли
"Places observed"
только при запуске приложения, например, если данные вообще не меняются…
Ответ №1:
Проблема не была связана с Room или шаблоном MVVM, это был побочный продукт моей невнимательности… Ошибка была в условии if в функции isValid () класса объектов place… Просто изменено
return mID == -1 amp;amp; mPosition.x != 0f amp;amp; mPosition.y != 0f amp;amp; mTokens >= 0
Для
return mID != -1 amp;amp; mPosition.x != 0f amp;amp; mPosition.y != 0f amp;amp; mTokens >= 0