From d579601de6490d58a6c24cb31c8e155a35e8d07a Mon Sep 17 00:00:00 2001 From: Gavriil Sitnikov Date: Fri, 14 Jul 2017 17:45:03 +0300 Subject: [PATCH] Comments added --- .../java/touchin/aacplusdbtest/ProfileActivity.kt | 4 +++- .../java/touchin/aacplusdbtest/ProfileRepository.kt | 13 ++++++++++--- .../java/touchin/aacplusdbtest/ProfileViewModel.kt | 13 ++++++++++++- .../aacplusdbtest/utils/LifecycleLiveDataField.kt | 1 + .../touchin/aacplusdbtest/utils/LiveDataField.kt | 2 +- 5 files changed, 27 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/touchin/aacplusdbtest/ProfileActivity.kt b/app/src/main/java/touchin/aacplusdbtest/ProfileActivity.kt index cd6dc79..82b6463 100644 --- a/app/src/main/java/touchin/aacplusdbtest/ProfileActivity.kt +++ b/app/src/main/java/touchin/aacplusdbtest/ProfileActivity.kt @@ -40,8 +40,10 @@ class ProfileActivity : LifecycleActivity() { override fun onDestroy() { super.onDestroy() + // обнуляем поле profileViewModel binding.profileViewModel = null + // необходимо вручную вызвать обновление байндингов, + // так как автоматическое обновление не работает на этапе onDestroy binding.executePendingBindings() } - } \ No newline at end of file diff --git a/app/src/main/java/touchin/aacplusdbtest/ProfileRepository.kt b/app/src/main/java/touchin/aacplusdbtest/ProfileRepository.kt index 71d551c..92990c6 100644 --- a/app/src/main/java/touchin/aacplusdbtest/ProfileRepository.kt +++ b/app/src/main/java/touchin/aacplusdbtest/ProfileRepository.kt @@ -25,6 +25,8 @@ import android.content.Context class ProfileRepository(context: Context) { private val loginKey = "login" private val preferences = context.getSharedPreferences("app_preferences", Context.MODE_PRIVATE) + // LiveData, на которую можно подписаться + // и получать обновления логина пользователя private val innerLoggedInUser = LoggedInUserLiveData() val loggedInUser: LiveData @@ -32,16 +34,22 @@ class ProfileRepository(context: Context) { fun login(login: String) { preferences.edit().putString(loginKey, login).apply() - innerLoggedInUser.update(login) + notifyAboutUpdate(login) } fun logout() { preferences.edit().putString(loginKey, null).apply() - innerLoggedInUser.update(null) + notifyAboutUpdate(null) + } + + private fun notifyAboutUpdate(login: String?) { + innerLoggedInUser.update(login) } private inner class LoggedInUserLiveData : LiveData() { + // так лучше не делать в конструкторе, а высчитывать текщее значение асинхронно + // при первом вызове колбека onActive init { value = preferences.getString(loginKey, null) } @@ -52,6 +60,5 @@ class ProfileRepository(context: Context) { fun update(login: String?) { postValue(login) } - } } diff --git a/app/src/main/java/touchin/aacplusdbtest/ProfileViewModel.kt b/app/src/main/java/touchin/aacplusdbtest/ProfileViewModel.kt index 4b424e6..aba6aa7 100644 --- a/app/src/main/java/touchin/aacplusdbtest/ProfileViewModel.kt +++ b/app/src/main/java/touchin/aacplusdbtest/ProfileViewModel.kt @@ -28,23 +28,34 @@ import touchin.aacplusdbtest.utils.TextField class ProfileViewModel(application: Application) : AndroidViewModel(application) { private val profileRepository: ProfileRepository = (application as AacPlusDbTestApp).profileRepository + // класс Transformations — это класс-хэлпер для преобразования данных + // метод map, просто конвертирует данные из одного типа в другой - в данном случае из String? в boolean + private val isUserLoggedInLiveData = Transformations.map(profileRepository.loggedInUser) { login -> login != null } // представляет логин авторизованного пользователя или null val userLogin = LifecycleLiveDataField(profileRepository.loggedInUser) // представляет авторизован ли пользователь - val isUserLoggedInLiveData = Transformations.map(profileRepository.loggedInUser) { login -> login != null } val isUserLoggedIn = LifecycleLiveDataField(isUserLoggedInLiveData) // представляет логин, введенный пользователем с клавиатуры + // TextField - это ObservableField, реализующий интерфейс TextWatcher + // это нужно, чтобы можно было байндиться к text и addTextChangedListener, + // организовав таким образом двустронний байндинг. + // При вводе текста в EditText изменяется ViewModel, при изменении ViewModel — изменяется в EditText. val inputLogin = TextField() fun loginOrLogout() { + // необходимо получить текущее состояние - авторизован пользователь или нет и решить, что делать isUserLoggedInLiveData.observeForever(object : Observer { override fun onChanged(loggedIn: Boolean?) { if (loggedIn!!) { profileRepository.logout() } else if (inputLogin.get() != null) { + // вызываем логин только если пользователь что-то ввел в поле ввода profileRepository.login(inputLogin.get()) + } else { + // по идее, тут можно отобразить ошибку "Введите логин" } + // при выполнении команды приходится отписываться вручную isUserLoggedInLiveData.removeObserver(this) } }) diff --git a/app/src/main/java/touchin/aacplusdbtest/utils/LifecycleLiveDataField.kt b/app/src/main/java/touchin/aacplusdbtest/utils/LifecycleLiveDataField.kt index a9d2186..2e3d3c7 100644 --- a/app/src/main/java/touchin/aacplusdbtest/utils/LifecycleLiveDataField.kt +++ b/app/src/main/java/touchin/aacplusdbtest/utils/LifecycleLiveDataField.kt @@ -38,6 +38,7 @@ class LifecycleLiveDataField(val source: LiveData) : ObservableField() override fun addOnPropertyChangedCallback(callback: Observable.OnPropertyChangedCallback) { super.addOnPropertyChangedCallback(callback) try { + // немножко рефлексии, по-другому никак val callbackListenerField = callback.javaClass.getDeclaredField("mListener") callbackListenerField.setAccessible(true) val callbackListener = callbackListenerField.get(callback) as WeakReference diff --git a/app/src/main/java/touchin/aacplusdbtest/utils/LiveDataField.kt b/app/src/main/java/touchin/aacplusdbtest/utils/LiveDataField.kt index 2d5e457..380f86c 100644 --- a/app/src/main/java/touchin/aacplusdbtest/utils/LiveDataField.kt +++ b/app/src/main/java/touchin/aacplusdbtest/utils/LiveDataField.kt @@ -26,7 +26,7 @@ import android.databinding.ObservableField import java.util.concurrent.atomic.AtomicInteger // наследуем от ObservableField -// имплементируем Observer (интерфейс из-подписчик для LiveData) чтобы синхронизировать значения LiveData и ObservableField +// имплементируем Observer (подписчик для LiveData) чтобы синхронизировать значения LiveData и ObservableField class LiveDataField(val source: LiveData) : ObservableField(), Observer { // отслеживаем количество подписчиков на этот ObservableField private var observersCount: AtomicInteger = AtomicInteger(0)