Я новичок в Kotlin и Android разработке. Я знаю, что здесь есть похожие, если не одни и те же вопросы. Да, я потратил целый день, пытаясь это выяснить.
Мне также жаль, что я не привел подходящего примера игрушки.
У меня простая цель. Я хочу, чтобы два EditText
"связали" вместе. Когда я меняю одну, я ожидаю, что другая тоже изменится. Я хочу применить шифр Цезаря (шифр реализован и работает). Но мы пока проигнорируем второе EditText
и сосредоточимся только на связывании первого.
Я читал, что современный способ достижения этого - использование DataBinding. Это звучит разумно, поскольку мне не нужно писать столько кода.
Однако, поскольку это «новая» функция, которая также изменилась, многие учебные пособия не дают мне полный пример кода, который я может просто использовать повторно. Я сам пытался реализовать это из кусочков в Интернете.
СВЯЗЬ НЕ РАБОТАЕТ!
У меня есть некоторый макет некоторого фрагмента (я пропускаю неважные вещи)
<layout>
<data>
<variable name="caesarViewModel" type="cz.fortescue.ui.caesar.CaesarViewModel"/>
</data>
<EditText
android:id="@+id/caesar_input"
android:inputType="text"
android:text="@={caesarViewModel.input}"/>
</layout>
Где "@={caesarViewModel.input}"
является важной частью. (не пропустите =
).
Теперь ViewModel.
class CaesarViewModel : ViewModel() {
val input = MutableLiveData<String>().apply {
value = "aaaaaa"
}
}
Я использую MutableLiveData
, поэтому DataBiding сможет изменить его. Я также использую apply
для проверки наблюдателя, который я покажу вам позже.
Последний, но не менее важный фрагмент
class CaesarFragment : Fragment() {
private lateinit var binding: FragmentCaesarBinding
private val caesarViewModel by lazy { ViewModelProvider(this).get(CaesarViewModel::class.java) }
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentCaesarBinding.inflate(
inflater,
container,
false
)
binding.caesarViewModel = caesarViewModel
binding.lifecycleOwner = viewLifecycleOwner
val root = inflater.inflate(R.layout.fragment_caesar, container, false)
caesarViewModel.input.observe(viewLifecycleOwner, Observer { text ->
caesarViewModel.output.value = encrypt(text) { caesarEncrypt(it, 1)}
Toast.makeText(context, text, Toast.LENGTH_SHORT).show()
})
return root
}
}
Поскольку я новичок в Kotlin, Я наполовину догадываюсь, что произойдет.
caesarViewModel
caesarViewModel
создается по мере необходимости. Обратите внимание, что я использую ViewModelProvider
не ViewModelProviders
.
binding
В Интернете было 5 разных способов, как правильно получить привязку. Я надеюсь, что это сейчас правильный. Я подозреваю здесь некоторые ошибки, но я не нашел никаких ...
Настройка членов
binding
Я устанавливаю lifecycleOwner
и caesarViewModel
. Последнее должно быть важной частью всей системы DataBinding.
Observer
Я создаю Observer, который должен уведомить меня с помощью Toast
, если что-то изменится. Он делает это один раз с aaaaaa
. Поскольку это значение, я применил к MutableLiveData
Я подозреваю, что наблюдатель работает очень хорошо.
Кажется, также необходимо изменить build.gradle
Плагины:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
android:
dataBinding {
enabled = true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
}
Зависимости:
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.2.0'
implementation 'com.google.android.material:material:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.navigation:navigation-fragment:2.2.1'
implementation 'androidx.navigation:navigation-ui:2.2.1'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.navigation:navigation-fragment-ktx:2.2.1'
implementation 'androidx.navigation:navigation-ui-ktx:2.2.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
Чего мне не хватает ??? Должно быть что-то, что я упустил из виду или о чем не знаю. В некоторых руководствах они используют декоратор @Bindable
, однако в MutableLiveData
.
это не требуется.