#kotlin #android-databinding
#котлин #android-привязка данных
Вопрос:
Я пытаюсь вызвать функцию, которая находится в «MainActivity.kt» из «content_main.xml» с помощью выражения привязки в onClick (как они на самом деле называются, атрибут?) пуговицы.
Проблема в том, что им никогда не звонят, когда я нажимаю восемь кнопок.
Вот как выглядит кодовый отрывок в «content_main.xml файл» (я исключил ненужный код для лучшей читабельности):
lt;?xml version="1.0" encoding="utf-8"?gt; lt;layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"gt; lt;datagt; lt;variable name="viewModel" type="com.ronnabyte.ntatools.model.FuelViewModel" /gt; lt;variable name="activity" type="com.ronnabyte.ntatools.MainActivity" /gt; lt;/datagt; lt;androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"gt; ... lt;Button android:id="@ id/clear_required_fuel_btn" style="@style/Widget.MaterialComponents.Button.OutlinedButton.Icon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="@{()-gt;activity.clearRequiredFuel()}" android:text="@string/clear_fuel_on_board" app:icon="@drawable/ic_baseline_delete_24" app:layout_constraintBottom_toBottomOf="@ id/required_fuel_ed" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@ id/required_fuel_ed" app:layout_constraintTop_toTopOf="@ id/required_fuel_ed" /gt; ... lt;Button android:id="@ id/clear_remaining_fuel_btn" style="@style/Widget.MaterialComponents.Button.OutlinedButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="@{()-gt;activity.clearRemainingFuel()}" android:text="@string/clear_fuel_on_board" app:icon="@drawable/ic_baseline_delete_24" app:layout_constraintBottom_toBottomOf="@ id/remaining_fuel_ed" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@ id/remaining_fuel_ed" app:layout_constraintTop_toTopOf="@ id/remaining_fuel_ed" /gt; ... lt;/androidx.constraintlayout.widget.ConstraintLayoutgt;
И код в «MainActivity.kt»:
package com.ronnabyte.ntatools import android.os.Bundle import android.util.Log import android.view.Menu import android.view.MenuItem import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.databinding.DataBindingUtil import androidx.lifecycle.LifecycleOwner import com.ronnabyte.ntatools.databinding.ActivityMainBinding import com.ronnabyte.ntatools.model.FuelViewModel class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding private val viewModel: FuelViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = DataBindingUtil.setContentView(this, R.layout.activity_main) setSupportActionBar(binding.toolbar) binding.fab.setOnClickListener { viewModel.calculateFuelUplift() } } override fun onCreateOptionsMenu(menu: Menu): Boolean { // Inflate the menu; this adds items to the action bar if it is present. menuInflater.inflate(R.menu.menu_main, menu) return true } override fun onOptionsItemSelected(item: MenuItem): Boolean { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. return when (item.itemId) { R.id.action_settings -gt; true else -gt; super.onOptionsItemSelected(item) } } fun clearRequiredFuel() { Log.d("MainActivity", "ClearRequiredFuel has been called.") binding.contentMain.apply { requiredFuelUpliftTv.text = "" requiredFuelEd.text.clear() requiredFuelEd.requestFocus() } } fun clearRemainingFuel() { Log.d("MainActivity", "ClearRemainingFuel has been called.") binding.contentMain.apply { requiredFuelUpliftTv.text = "" remainingFuelEd.text.clear() requiredFuelEd.requestFocus() } }
Любая помощь приветствуется, большое спасибо.
Изменить: вот файл gradle:
plugins { id 'com.android.application' id 'kotlin-android' id 'kotlin-kapt' } android { compileSdk 31 defaultConfig { applicationId "com.ronnabyte.ntatools" minSdk 26 targetSdk 31 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android- optimize.txt'), 'proguard-rules.pro' } } buildFeatures { dataBinding true } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = '1.8' } } dependencies { implementation 'androidx.appcompat:appcompat:1.4.0' implementation 'com.google.android.material:material:1.4.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.2' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0' implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.0" implementation 'androidx.core:core-ktx:1.7.0' implementation 'androidx.fragment:fragment-ktx:1.4.0'
}
Комментарии:
1. Что делать, если перенести эти методы
ViewModel
вMainActivity
подписку наViewModel
LiveData и в нее?2. Даже если бы я знал, как это сделать, разве это не противоречило бы архитектуре ViewModel, которая гласит, что ViewModel не должен знать о представлениях? Я устанавливаю представления в этих двух функциях… Прошу прощения, я довольно новичок в этом деле.
3. Я думаю, что мое предположение неверно. Но в отношении
ViewModel
этого не было бы ничего плохого. Вы будете иметьLiveData
илиMutableStateFlow
вViewModel
и установите его значение там. Затем вMainActivity
вы подпишетесь на это значение отViewModel
. Когда данныеViewModel
изменятся (LiveData или MutableStateFlow изменят свое значение), подписчик также отразит изменения (requiredFuelUpliftTv.text = ""
и т. Д.).
Ответ №1:
Я нашел проблему, почему binding.activity = this
это не работало. binding
имеет тип ActivityMainBinding
, но переменная activity
была определена в content_main.xml
вместо activity_main.xml
.
Вот почему его нельзя было найти на переплете, поэтому он все время становился красным.
Ответ №2:
внесите эти небольшие изменения в свой код:
private lateinit var binding: ActivityMainBinding private val viewModel: FuelViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { binding super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) //lt;-- setContentView(binding.root) //lt;-- setSupportActionBar(binding.toolbar)
Комментарии:
1. Это не работает, код запускается через корыто, но функция по-прежнему не вызывается, когда я нажимаю кнопки (кнопки).
Ответ №3:
Добавьте эту строку в свой onCreate
метод:
binding.activity = this
Демо-код ниже:
class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = DataBindingUtil.setContentView(this, R.layout.activity_main) // without this line, test() will not called binding.activity = this } fun test() { Log.d("test", "test") } }
lt;?xml version="1.0" encoding="utf-8"?gt; lt;layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"gt; lt;datagt; lt;variable name="activity" type="com.example.myapplication.MainActivity" /gt; lt;/datagt; lt;androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"gt; lt;Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="@{() -gt; activity.test()}" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /gt; lt;/androidx.constraintlayout.widget.ConstraintLayoutgt; lt;/layoutgt;
Комментарии:
1. К сожалению, это не работает, я получаю «Неразрешенную ссылку» на действие.
2. Какая переменная не решена? Я написал демо-версию для тестирования, и она сработала. Пожалуйста, проверьте мой отредактированный ответ.
3. Большое спасибо, что изучили это, очень признателен. Когда я начинаю новый проект и использую предоставленный вами код, он отлично работает, как вы и сказали. Но когда я пробую строку «привязка.активность = это» в своем проекте,». активность» становится красной с подсказкой «Неразрешенная ссылка: активность». Но «привязка» имеет тот же тип, что и в примере, который работает, а именно тип «частная окончательная привязка lateinit var: ActivityMainBinding». Я очистил и восстановил проект безрезультатно. Я постараюсь включить файл gradle, чтобы вы могли посмотреть, если у вас будет время. Большое спасибо.