LiveData работает с повторным представлением, а MutableLiveData - нет. Почему? - PullRequest
1 голос
/ 23 октября 2019

Сценарий таков:

Дао:

@Dao
interface TipDAO {
    @Query("SELECT * FROM tip_table")
    fun getAll(): LiveData<List<Tip>>

    @Query("SELECT * FROM tip_table WHERE title LIKE :title")
    fun findByName(title: String): Tip

    @Query("SELECT * from tip_table ORDER BY title DESC")
    fun getAlphabetizedTips(): LiveData<List<Tip>>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insert(vararg tip: Tip)

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertAll(vararg tips: Tip)

    @Delete
    suspend fun delete(tip: Tip)

    @Query("DELETE FROM tip_table")
    suspend fun deleteAll()

Репозиторий:


class TipRepository (private val tipDAO: TipDAO){

    // Room executes all queries on a separate thread.
    // Observed LiveData will notify the observer when the data has changed.
    val allTips: LiveData<List<Tip>> = tipDAO.getAll()

    // The suspend modifier tells the compiler that this must be called from a
    // coroutine or another suspend function.

    suspend fun insert (tip: Tip){
        tipDAO.insert(tip)
    }

    fun getAlphabetizedTips (): LiveData<List<Tip>> {
        return tipDAO.getAlphabetizedTips()
    }

    suspend fun delete (tip: Tip) {
        tipDAO.delete(tip)
    }

Представление модели

class TipViewModel (application: Application): AndroidViewModel (application) {

    private val repository : TipRepository
    val allTips: LiveData<List<Tip>>


    init {
        val tipDAO = TipRoomDatabase.getDatabase(application).tipDao()
        repository = TipRepository(tipDAO)
        allTips = repository.allTips
    }

    fun insert (tip: Tip) = viewModelScope.launch {
        repository.insert(tip)
    }

    fun delete (tip: Tip)  = viewModelScope.launch {
        repository.delete(tip)
    }

    fun getAlphabetizedTips () {
        //How I can query so I can see the change ????¿¿¿¿
    }


}

Активность

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_how_to)

        val recyclerView: RecyclerView = findViewById (R.id.content)
        val adapter = TipListAdapter(this)

        recyclerView.adapter = adapter
        recyclerView.layoutManager = LinearLayoutManager(this)
        recyclerView.isNestedScrollingEnabled = false

        tipViewModel = ViewModelProvider(this,ViewModelProvider.AndroidViewModelFactory(this.application))
            .get(TipViewModel::class.java)

        tipViewModel.allTips.observe(this,
            Observer<List<Tip>> { tips ->
                // Update the cached copy of the tips in the adapter.
                tips?.let { adapter.setTips(tips)} //setTips notify the listener
            })

        val addButton: Button = findViewById(R.id.how_to_add_bt)
        val delButton: Button = findViewById(R.id.how_to_delete_bt)
        val sortButton: ImageButton = findViewById(R.id.how_to_sort_bt)
        val searchBar: TextView = findViewById(R.id.how_to_search_bar)

        addButton.setOnClickListener {
          Toast.makeText(this,"ADD", Toast.LENGTH_SHORT).show()
          intent = Intent(this, AddActivity::class.java)
          startActivityForResult(intent, NEW_TIP_ACTIVITY_REQUEST_CODE)
        }

        delButton.setOnClickListener {
            TipListAdapter.delete = !TipListAdapter.delete //changes a flag 
        }

        sortButton.setOnClickListener {
            tipViewModel.getAlphabetizedTips()
        }
///more irrelevant code

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        if (NEW_TIP_ACTIVITY_REQUEST_CODE == requestCode && resultCode == RESULT_OK && data!= null) {
            data.let{
                val description: String = it.getStringExtra(AddActivity.DESCRIPTION)!!
                val title: String = it.getStringExtra(AddActivity.TITLE)!!
                val image: String =  it.getStringExtra(AddActivity.IMAGE)!!
                Toast.makeText(this, "You have created a tip succesfully",Toast.LENGTH_SHORT).show()
                val tip = Tip (null,title, image, description)
                tipViewModel.insert(tip)
            }
        } else {
            Toast.makeText(this,"The tip was not uploaded correctly",Toast.LENGTH_SHORT).show()
        }
    }

Ситуация такова, что я использую LiveData для allTips в Модель , она корректно отображается в RecycleView. Но если я использую MutableLiveData, то ничего не отображается. Моя цель - использовать MutableLiveData для выполнения запросов, и наблюдатель получит уведомление об изменении данных повторного просмотра. Мои вопросы:

  • В модели представления, как я могу изменить значение allDips LiveData для каждого запроса, который я делаю? то есть: getAlphabetizedTips, getTip (title) и т. д.
  • Почему MutableLiveData не работает как код фрагмента следующим образом?

[EDIT]

Вид модели с MutableLiveData

class TipViewModel (application: Application): AndroidViewModel (application) {

    private val repository : TipRepository
    val allTips: MutableLiveData<List<Tip>>


    init {
        val tipDAO = TipRoomDatabase.getDatabase(application).tipDao()
        repository = TipRepository(tipDAO)
        allTips.value = repository.allTips.value
    }

    fun insert (tip: Tip) = viewModelScope.launch {
        repository.insert(tip)
    }

    fun delete (tip: Tip)  = viewModelScope.launch {
        repository.delete(tip)
    }

    fun getAlphabetizedTips () {
        //How I can query so I can see the change ????¿¿¿¿
        allTips.post(respository.getAlphabetizedTips.value) 
    }


}

1 Ответ

1 голос
/ 23 октября 2019

Попробуйте MediatorLiveData вместо изменяемого

Репозиторий:

class TipRepository (private val tipDAO: TipDAO){

    // Room executes all queries on a separate thread.
    // Observed LiveData will notify the observer when the data has changed.
    val allTips: LiveData<List<Tip>> = tipDAO.getAll()

    // The suspend modifier tells the compiler that this must be called from a
    // coroutine or another suspend function.

    suspend fun insert (tip: Tip){
        tipDAO.insert(tip)
    }

    fun getAlphabetizedTips (): LiveData<List<Tip>> {
        return tipDAO.getAlphabetizedTips()
    }

    suspend fun delete (tip: Tip) {
        tipDAO.delete(tip)
    }

Вид модели

class TipViewModel (application: Application): AndroidViewModel (application) {

    private val repository : TipRepository
    val allTips = MediatorLiveData<List<Tip>()


    init {
        val tipDAO = TipRoomDatabase.getDatabase(application).tipDao()
        repository = TipRepository(tipDAO)
        allTips.addSource(repository.allTips){
          this.allTips.value = it
       }
    }
...