Как наблюдать за данными, сгенерированными из пользовательского вида поверхности

#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