#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-макета, если вы используете привязку данных. Возможно, вы также захотите рассмотреть возможность использования интерфейса, который обеспечивает любые взаимодействия с пользовательским интерфейсом.