Android: Вызов функции ViewModel с привязкой данных

#android #binding #android-jetpack

#Android #привязка #android-реактивный ранец

Вопрос:

Я пытаюсь использовать привязку данных для настройки прослушивателей onClick для кнопок в моем фрагменте.

Функция, которую мне нужно вызывать при каждом нажатии кнопки «далее», находится в модели представления.

Мне удалось привязать данные из модели представления к моему макету XML, но я все еще не могу вызывать функции из модели представления :/

Я получаю эту ошибку при попытке вызвать функции ViewModel:

 C:UsersMichalgitfitness-fatalityappbuildgeneratedsourcekaptdebugcomexamplefitnessfatalityDataBinderMapperImpl.java:10: error: cannot find symbol
import com.example.fitnessfatality.databinding.FragmentWorkoutLoggingBindingImpl;
                                              ^
  symbol:   class FragmentWorkoutLoggingBindingImpl
  location: package com.example.fitnessfatality.databinding
  

Я также пытался вызывать функции модели просмотра следующим образом:

 android:onClick="@{viewModel.incrementIndex()}"
  

Однако, если я свяжу весь фрагмент, я смогу вызывать его функции.

Вот как я пытался реализовать привязку по щелчку с помощью модели представления:

 <?xml version="1.0" encoding="utf-8"?>
<layout
        android:id="@ id/main_linear_container"
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <import type="com.example.fitnessfatality.ui.workoutTracking.viewModels.TrackingViewModel"/>
        <import type="java.util.List"/>
        <import type="com.example.fitnessfatality.ui.workoutTracking.TrackingFragment" />
        <variable name="viewModel" type="TrackingViewModel" />
        <variable name="fragment" type="TrackingFragment" />
    </data>

    <LinearLayout
            android:orientation="vertical" android:layout_height="match_parent" android:layout_width="match_parent">

//More layouts


                <Button
                        android:text="Next"
                        android:onClick="@{viewModel.incrementIndex}"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content" android:id="@ id/btn_next" android:layout_weight="1"/>
        </LinearLayout>
</layout>
  

И в моем фрагменте у меня есть

  private lateinit var trackingViewModel: TrackingViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        trackingViewModel = ViewModelProviders.of(this).get(TrackingViewModel::class.java)
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val binding =
            DataBindingUtil.inflate<FragmentWorkoutLoggingBinding>(
                inflater,
                R.layout.fragment_workout_logging,
                container,
                false
            )

        binding.lifecycleOwner = this
        binding.viewModel = trackingViewModel
        binding.fragment = this

        return binding.root
    }
  

И моя ViewModel:

 class TrackingViewModel(application: Application): BaseViewModel(application) {
    val workoutExercises: LiveData<List<WorkoutExercisePojo>>
    private val workoutExerciseRepository: WorkoutExerciseRepository

    val currentIndex: MutableLiveData<Int> = MutableLiveData()

    val index: LiveData<Int> = currentIndex

    init {
        val db = AppDatabase.getDatabase(application, scope)
        workoutExerciseRepository = WorkoutExerciseRepository(db.workoutExerciseDao())
        workoutExercises = workoutExerciseRepository.allWorkoutExercises
        currentIndex.value = 0
    }

    fun incrementIndex() {
        currentIndex.value = currentIndex.value!!.plus(1)
    }
}
  

Комментарии:

1. «Я все еще не могу вызывать функции из модели представления» — что это значит? Каковы ваши симптомы? Я бы ожидал, что выражение привязки @{viewModel.incrementIndex()} будет работать.

2. При попытке я получаю сообщение об ошибке в сгенерированных файлах @{viewModel.incrementIndex()} . Я обновил свое описание сообщением об ошибке

3. «Я получаю эту ошибку при попытке вызвать функции ViewModel» — если вы посмотрите на вывод сборки, вы должны получать другие сообщения об ошибках, связанные с ресурсами компоновки привязки данных.

4. Я нет, я получаю только ошибку, которую я добавил в описание в консоли сборки

Ответ №1:

С пользовательским адаптером привязки:

 @BindingAdapter("onClick")
fun onClick(view: View, onClick: () -> Unit) {
    view.setOnClickListener {
        onClick()
    }
}
  

Вы должны иметь возможность напрямую привязывать функцию viewmodel, например

 app:onClick="@{viewModel::forgotPasswordClicked}"
  

в вашем XML. Затем это приведет к функции viewmodel, например:

 fun forgotPasswordClicked() {
    TODO("ForgotPasswordClicked")
}
  

Таким образом, вам также не нужно импортировать ненужные зависимости Android в вашу viewmodel.

Комментарии:

1. его лучше использовать android:onClick-"@{()->vm.yourFun()}" , работает без импорта классов Android и нет необходимости создавать адаптер привязки

Ответ №2:

Удалось решить. Проблема заключалась в том, что incremenetIndex функция в ViewModel не принимала View в качестве параметра.

Итак, теперь функция в ViewModel выглядит следующим образом:

 fun incrementIndex(view: View) {
    currentIndex.value = currentIndex.value!!.plus(1)
}
  

Комментарии:

1. Как вы передавали view аргумент при вызове этой функции из XML?

2. Я точно не помню, как я это сделал тогда, но вы можете передавать view из своего фрагмента при вызове функции или из XML-макета, если вы используете привязку данных. Возможно, вы также захотите рассмотреть возможность использования интерфейса, который обеспечивает любые взаимодействия с пользовательским интерфейсом.